##// END OF EJS Templates
feat(system-info): expose rhodecode config for better visibility of set settings
super-admin -
r5552:f3356a66 default
parent child Browse files
Show More
@@ -1,249 +1,253 b''
1
1
2
2
3 # Copyright (C) 2016-2023 RhodeCode GmbH
3 # Copyright (C) 2016-2023 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 import urllib.request
22 import urllib.request
23 import urllib.error
23 import urllib.error
24 import urllib.parse
24 import urllib.parse
25 import os
25 import os
26
26
27 import rhodecode
27 import rhodecode
28 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base import BaseAppView
29 from rhodecode.apps._base.navigation import navigation_list
29 from rhodecode.apps._base.navigation import navigation_list
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
32 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.lib.utils2 import str2bool
33 from rhodecode.lib import system_info
33 from rhodecode.lib import system_info
34 from rhodecode.model.update import UpdateModel
34 from rhodecode.model.update import UpdateModel
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class AdminSystemInfoSettingsView(BaseAppView):
39 class AdminSystemInfoSettingsView(BaseAppView):
40 def load_default_context(self):
40 def load_default_context(self):
41 c = self._get_local_tmpl_context()
41 c = self._get_local_tmpl_context()
42 return c
42 return c
43
43
44 def get_env_data(self):
44 def get_env_data(self):
45 black_list = [
45 black_list = [
46 'NIX_LDFLAGS',
46 'NIX_LDFLAGS',
47 'NIX_CFLAGS_COMPILE',
47 'NIX_CFLAGS_COMPILE',
48 'propagatedBuildInputs',
48 'propagatedBuildInputs',
49 'propagatedNativeBuildInputs',
49 'propagatedNativeBuildInputs',
50 'postInstall',
50 'postInstall',
51 'buildInputs',
51 'buildInputs',
52 'buildPhase',
52 'buildPhase',
53 'preShellHook',
53 'preShellHook',
54 'preShellHook',
54 'preShellHook',
55 'preCheck',
55 'preCheck',
56 'preBuild',
56 'preBuild',
57 'postShellHook',
57 'postShellHook',
58 'postFixup',
58 'postFixup',
59 'postCheck',
59 'postCheck',
60 'nativeBuildInputs',
60 'nativeBuildInputs',
61 'installPhase',
61 'installPhase',
62 'installCheckPhase',
62 'installCheckPhase',
63 'checkPhase',
63 'checkPhase',
64 'configurePhase',
64 'configurePhase',
65 'shellHook'
65 'shellHook'
66 ]
66 ]
67 secret_list = [
67 secret_list = [
68 'RHODECODE_USER_PASS'
68 'RHODECODE_USER_PASS'
69 ]
69 ]
70
70
71 for k, v in sorted(os.environ.items()):
71 for k, v in sorted(os.environ.items()):
72 if k in black_list:
72 if k in black_list:
73 continue
73 continue
74 if k in secret_list:
74 if k in secret_list:
75 v = '*****'
75 v = '*****'
76 yield k, v
76 yield k, v
77
77
78 @LoginRequired()
78 @LoginRequired()
79 @HasPermissionAllDecorator('hg.admin')
79 @HasPermissionAllDecorator('hg.admin')
80 def settings_system_info(self):
80 def settings_system_info(self):
81 _ = self.request.translate
81 _ = self.request.translate
82 c = self.load_default_context()
82 c = self.load_default_context()
83
83
84 c.active = 'system'
84 c.active = 'system'
85 c.navlist = navigation_list(self.request)
85 c.navlist = navigation_list(self.request)
86
86
87 # TODO(marcink), figure out how to allow only selected users to do this
87 # TODO(marcink), figure out how to allow only selected users to do this
88 c.allowed_to_snapshot = self._rhodecode_user.admin
88 c.allowed_to_snapshot = self._rhodecode_user.admin
89
89
90 snapshot = str2bool(self.request.params.get('snapshot'))
90 snapshot = str2bool(self.request.params.get('snapshot'))
91
91
92 c.rhodecode_update_url = UpdateModel().get_update_url()
92 c.rhodecode_update_url = UpdateModel().get_update_url()
93 c.env_data = self.get_env_data()
93 c.env_data = self.get_env_data()
94 server_info = system_info.get_system_info(self.request.environ)
94 server_info = system_info.get_system_info(self.request.environ)
95
95
96 for key, val in server_info.items():
96 for key, val in server_info.items():
97 setattr(c, key, val)
97 setattr(c, key, val)
98
98
99 def val(name, subkey='human_value'):
99 def val(name, subkey='human_value'):
100 return server_info[name][subkey]
100 return server_info[name][subkey]
101
101
102 def state(name):
102 def state(name):
103 return server_info[name]['state']
103 return server_info[name]['state']
104
104
105 def val2(name):
105 def val2(name):
106 val = server_info[name]['human_value']
106 val = server_info[name]['human_value']
107 state = server_info[name]['state']
107 state = server_info[name]['state']
108 return val, state
108 return val, state
109
109
110 update_info_msg = _('Note: please make sure this server can '
110 update_info_msg = _('Note: please make sure this server can '
111 'access `${url}` for the update link to work',
111 'access `${url}` for the update link to work',
112 mapping=dict(url=c.rhodecode_update_url))
112 mapping=dict(url=c.rhodecode_update_url))
113 version = UpdateModel().get_stored_version()
113 version = UpdateModel().get_stored_version()
114 is_outdated = UpdateModel().is_outdated(
114 is_outdated = UpdateModel().is_outdated(
115 rhodecode.__version__, version)
115 rhodecode.__version__, version)
116 update_state = {
116 update_state = {
117 'type': 'warning',
117 'type': 'warning',
118 'message': 'New version available: {}'.format(version)
118 'message': 'New version available: {}'.format(version)
119 } \
119 } \
120 if is_outdated else {}
120 if is_outdated else {}
121 c.data_items = [
121 c.data_items = [
122 # update info
122 # update info
123 (_('Update info'), h.literal(
123 (_('Update info'), h.literal(
124 '<span class="link" id="check_for_update" >%s.</span>' % (
124 '<span class="link" id="check_for_update" >%s.</span>' % (
125 _('Check for updates')) +
125 _('Check for updates')) +
126 '<br/> <span >%s.</span>' % (update_info_msg)
126 '<br/> <span >%s.</span>' % (update_info_msg)
127 ), ''),
127 ), ''),
128
128
129 # RhodeCode specific
129 # RhodeCode specific
130 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
130 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
131 (_('Latest version'), version, update_state),
131 (_('Latest version'), version, update_state),
132 (_('RhodeCode Base URL'), val('rhodecode_config')['config'].get('app.base_url'), state('rhodecode_config')),
132 (_('RhodeCode Base URL'), val('rhodecode_config')['config'].get('app.base_url'), state('rhodecode_config')),
133 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
133 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
134 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
134 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
135 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
135 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
136 (_('RhodeCode Certificate'), val('rhodecode_config')['cert_path'], state('rhodecode_config')),
136 (_('RhodeCode Certificate'), val('rhodecode_config')['cert_path'], state('rhodecode_config')),
137 (_('Workers'), val('rhodecode_config')['config']['server:main'].get('workers', '?'), state('rhodecode_config')),
137 (_('Workers'), val('rhodecode_config')['config']['server:main'].get('workers', '?'), state('rhodecode_config')),
138 (_('Worker Type'), val('rhodecode_config')['config']['server:main'].get('worker_class', 'sync'), state('rhodecode_config')),
138 (_('Worker Type'), val('rhodecode_config')['config']['server:main'].get('worker_class', 'sync'), state('rhodecode_config')),
139 ('', '', ''), # spacer
139 ('', '', ''), # spacer
140
140
141 # Database
141 # Database
142 (_('Database'), val('database')['url'], state('database')),
142 (_('Database'), val('database')['url'], state('database')),
143 (_('Database version'), val('database')['version'], state('database')),
143 (_('Database version'), val('database')['version'], state('database')),
144 ('', '', ''), # spacer
144 ('', '', ''), # spacer
145
145
146 # Platform/Python
146 # Platform/Python
147 (_('Platform'), val('platform')['name'], state('platform')),
147 (_('Platform'), val('platform')['name'], state('platform')),
148 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
148 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
149 (_('Lang'), val('locale'), state('locale')),
149 (_('Lang'), val('locale'), state('locale')),
150 (_('Python version'), val('python')['version'], state('python')),
150 (_('Python version'), val('python')['version'], state('python')),
151 (_('Python path'), val('python')['executable'], state('python')),
151 (_('Python path'), val('python')['executable'], state('python')),
152 ('', '', ''), # spacer
152 ('', '', ''), # spacer
153
153
154 # Systems stats
154 # Systems stats
155 (_('CPU'), val('cpu')['text'], state('cpu')),
155 (_('CPU'), val('cpu')['text'], state('cpu')),
156 (_('Load'), val('load')['text'], state('load')),
156 (_('Load'), val('load')['text'], state('load')),
157 (_('Memory'), val('memory')['text'], state('memory')),
157 (_('Memory'), val('memory')['text'], state('memory')),
158 (_('Uptime'), val('uptime')['text'], state('uptime')),
158 (_('Uptime'), val('uptime')['text'], state('uptime')),
159 ('', '', ''), # spacer
159 ('', '', ''), # spacer
160
160
161 # ulimit
161 # ulimit
162 (_('Ulimit'), val('ulimit')['text'], state('ulimit')),
162 (_('Ulimit'), val('ulimit')['text'], state('ulimit')),
163
163
164 # Repo storage
164 # Repo storage
165 (_('Storage location'), val('storage')['path'], state('storage')),
165 (_('Storage location'), val('storage')['path'], state('storage')),
166 (_('Storage info'), val('storage')['text'], state('storage')),
166 (_('Storage info'), val('storage')['text'], state('storage')),
167 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
167 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
168 ('', '', ''), # spacer
168 ('', '', ''), # spacer
169
169
170 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
170 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
171 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
171 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
172 ('', '', ''), # spacer
172 ('', '', ''), # spacer
173
173
174 (_('Artifacts storage backend'), val('storage_artifacts')['type'], state('storage_artifacts')),
174 (_('Artifacts storage backend'), val('storage_artifacts')['type'], state('storage_artifacts')),
175 (_('Artifacts storage location'), val('storage_artifacts')['path'], state('storage_artifacts')),
175 (_('Artifacts storage location'), val('storage_artifacts')['path'], state('storage_artifacts')),
176 (_('Artifacts info'), val('storage_artifacts')['text'], state('storage_artifacts')),
176 (_('Artifacts info'), val('storage_artifacts')['text'], state('storage_artifacts')),
177 ('', '', ''), # spacer
177 ('', '', ''), # spacer
178
178
179 (_('Archive cache storage backend'), val('storage_archive')['type'], state('storage_archive')),
179 (_('Archive cache storage backend'), val('storage_archive')['type'], state('storage_archive')),
180 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
180 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
181 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
181 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
182 ('', '', ''), # spacer
182 ('', '', ''), # spacer
183
183
184
184
185 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
185 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
186 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
186 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
187 ('', '', ''), # spacer
187 ('', '', ''), # spacer
188
188
189 (_('Search info'), val('search')['text'], state('search')),
189 (_('Search info'), val('search')['text'], state('search')),
190 (_('Search location'), val('search')['location'], state('search')),
190 (_('Search location'), val('search')['location'], state('search')),
191 ('', '', ''), # spacer
191 ('', '', ''), # spacer
192
192
193 # VCS specific
193 # VCS specific
194 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
194 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
195 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
195 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
196 (_('GIT'), val('git'), state('git')),
196 (_('GIT'), val('git'), state('git')),
197 (_('HG'), val('hg'), state('hg')),
197 (_('HG'), val('hg'), state('hg')),
198 (_('SVN'), val('svn'), state('svn')),
198 (_('SVN'), val('svn'), state('svn')),
199
199
200 ]
200 ]
201
201
202 c.rhodecode_data_items = [
203 (k, v) for k, v in sorted((val('rhodecode_server_config') or {}).items(), key=lambda x: x[0].lower())
204 ]
205
202 c.vcsserver_data_items = [
206 c.vcsserver_data_items = [
203 (k, v) for k, v in (val('vcs_server_config') or {}).items()
207 (k, v) for k, v in sorted((val('vcs_server_config') or {}).items(), key=lambda x: x[0].lower())
204 ]
208 ]
205
209
206 if snapshot:
210 if snapshot:
207 if c.allowed_to_snapshot:
211 if c.allowed_to_snapshot:
208 c.data_items.pop(0) # remove server info
212 c.data_items.pop(0) # remove server info
209 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
213 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
210 else:
214 else:
211 h.flash('You are not allowed to do this', category='warning')
215 h.flash('You are not allowed to do this', category='warning')
212 return self._get_template_context(c)
216 return self._get_template_context(c)
213
217
214 @LoginRequired()
218 @LoginRequired()
215 @HasPermissionAllDecorator('hg.admin')
219 @HasPermissionAllDecorator('hg.admin')
216 def settings_system_info_check_update(self):
220 def settings_system_info_check_update(self):
217 _ = self.request.translate
221 _ = self.request.translate
218 c = self.load_default_context()
222 c = self.load_default_context()
219
223
220 update_url = UpdateModel().get_update_url()
224 update_url = UpdateModel().get_update_url()
221
225
222 def _err(s):
226 def _err(s):
223 return f'<div style="color:#ff8888; padding:4px 0px">{s}</div>'
227 return f'<div style="color:#ff8888; padding:4px 0px">{s}</div>'
224
228
225 try:
229 try:
226 data = UpdateModel().get_update_data(update_url)
230 data = UpdateModel().get_update_data(update_url)
227 except urllib.error.URLError as e:
231 except urllib.error.URLError as e:
228 log.exception("Exception contacting upgrade server")
232 log.exception("Exception contacting upgrade server")
229 self.request.override_renderer = 'string'
233 self.request.override_renderer = 'string'
230 return _err('Failed to contact upgrade server: %r' % e)
234 return _err('Failed to contact upgrade server: %r' % e)
231 except ValueError as e:
235 except ValueError as e:
232 log.exception("Bad data sent from update server")
236 log.exception("Bad data sent from update server")
233 self.request.override_renderer = 'string'
237 self.request.override_renderer = 'string'
234 return _err('Bad data sent from update server')
238 return _err('Bad data sent from update server')
235
239
236 latest = data['versions'][0]
240 latest = data['versions'][0]
237
241
238 c.update_url = update_url
242 c.update_url = update_url
239 c.latest_data = latest
243 c.latest_data = latest
240 c.latest_ver = (latest['version'] or '').strip()
244 c.latest_ver = (latest['version'] or '').strip()
241 c.cur_ver = self.request.GET.get('ver') or rhodecode.__version__
245 c.cur_ver = self.request.GET.get('ver') or rhodecode.__version__
242 c.should_upgrade = False
246 c.should_upgrade = False
243
247
244 is_outdated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
248 is_outdated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
245 if is_outdated:
249 if is_outdated:
246 c.should_upgrade = True
250 c.should_upgrade = True
247 c.important_notices = latest['general']
251 c.important_notices = latest['general']
248 UpdateModel().store_version(latest['version'])
252 UpdateModel().store_version(latest['version'])
249 return self._get_template_context(c)
253 return self._get_template_context(c)
@@ -1,866 +1,893 b''
1 # Copyright (C) 2017-2023 RhodeCode GmbH
1 # Copyright (C) 2017-2023 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19
19
20 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 import platform
23 import platform
24 import collections
24 import collections
25 import psutil
25 import psutil
26 from functools import wraps
26 from functools import wraps
27
27
28 import pkg_resources
28 import pkg_resources
29 import logging
29 import logging
30 import resource
30 import resource
31
31
32 import configparser
32 import configparser
33
33
34 from rc_license.models import LicenseModel
34 from rc_license.models import LicenseModel
35 from rhodecode.lib.str_utils import safe_str
35 from rhodecode.lib.str_utils import safe_str
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 _NA = 'NOT AVAILABLE'
40 _NA = 'NOT AVAILABLE'
41 _NA_FLOAT = 0.0
41 _NA_FLOAT = 0.0
42
42
43 STATE_OK = 'ok'
43 STATE_OK = 'ok'
44 STATE_ERR = 'error'
44 STATE_ERR = 'error'
45 STATE_WARN = 'warning'
45 STATE_WARN = 'warning'
46
46
47 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
47 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
48
48
49
49
50 registered_helpers = {}
50 registered_helpers = {}
51
51
52
52
53 def register_sysinfo(func):
53 def register_sysinfo(func):
54 """
54 """
55 @register_helper
55 @register_helper
56 def db_check():
56 def db_check():
57 pass
57 pass
58
58
59 db_check == registered_helpers['db_check']
59 db_check == registered_helpers['db_check']
60 """
60 """
61 global registered_helpers
61 global registered_helpers
62 registered_helpers[func.__name__] = func
62 registered_helpers[func.__name__] = func
63
63
64 @wraps(func)
64 @wraps(func)
65 def _wrapper(*args, **kwargs):
65 def _wrapper(*args, **kwargs):
66 return func(*args, **kwargs)
66 return func(*args, **kwargs)
67 return _wrapper
67 return _wrapper
68
68
69
69
70 # HELPERS
70 # HELPERS
71 def percentage(part: (int, float), whole: (int, float)):
71 def percentage(part: (int, float), whole: (int, float)):
72 whole = float(whole)
72 whole = float(whole)
73 if whole > 0:
73 if whole > 0:
74 return round(100 * float(part) / whole, 1)
74 return round(100 * float(part) / whole, 1)
75 return 0.0
75 return 0.0
76
76
77
77
78 def get_storage_size(storage_path):
78 def get_storage_size(storage_path):
79 sizes = []
79 sizes = []
80 for file_ in os.listdir(storage_path):
80 for file_ in os.listdir(storage_path):
81 storage_file = os.path.join(storage_path, file_)
81 storage_file = os.path.join(storage_path, file_)
82 if os.path.isfile(storage_file):
82 if os.path.isfile(storage_file):
83 try:
83 try:
84 sizes.append(os.path.getsize(storage_file))
84 sizes.append(os.path.getsize(storage_file))
85 except OSError:
85 except OSError:
86 log.exception('Failed to get size of storage file %s', storage_file)
86 log.exception('Failed to get size of storage file %s', storage_file)
87 pass
87 pass
88
88
89 return sum(sizes)
89 return sum(sizes)
90
90
91
91
92 def get_resource(resource_type):
92 def get_resource(resource_type):
93 try:
93 try:
94 return resource.getrlimit(resource_type)
94 return resource.getrlimit(resource_type)
95 except Exception:
95 except Exception:
96 return 'NOT_SUPPORTED'
96 return 'NOT_SUPPORTED'
97
97
98
98
99 def get_cert_path(ini_path):
99 def get_cert_path(ini_path):
100 default = '/etc/ssl/certs/ca-certificates.crt'
100 default = '/etc/ssl/certs/ca-certificates.crt'
101 control_ca_bundle = os.path.join(
101 control_ca_bundle = os.path.join(
102 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(ini_path)))),
102 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(ini_path)))),
103 '/etc/ssl/certs/ca-certificates.crt')
103 '/etc/ssl/certs/ca-certificates.crt')
104 if os.path.isfile(control_ca_bundle):
104 if os.path.isfile(control_ca_bundle):
105 default = control_ca_bundle
105 default = control_ca_bundle
106
106
107 return default
107 return default
108
108
109
109
110 class SysInfoRes(object):
110 class SysInfoRes(object):
111 def __init__(self, value, state=None, human_value=None):
111 def __init__(self, value, state=None, human_value=None):
112 self.value = value
112 self.value = value
113 self.state = state or STATE_OK_DEFAULT
113 self.state = state or STATE_OK_DEFAULT
114 self.human_value = human_value or value
114 self.human_value = human_value or value
115
115
116 def __json__(self):
116 def __json__(self):
117 return {
117 return {
118 'value': self.value,
118 'value': self.value,
119 'state': self.state,
119 'state': self.state,
120 'human_value': self.human_value,
120 'human_value': self.human_value,
121 }
121 }
122
122
123 def get_value(self):
123 def get_value(self):
124 return self.__json__()
124 return self.__json__()
125
125
126 def __str__(self):
126 def __str__(self):
127 return f'<SysInfoRes({self.__json__()})>'
127 return f'<SysInfoRes({self.__json__()})>'
128
128
129
129
130 class SysInfo(object):
130 class SysInfo(object):
131
131
132 def __init__(self, func_name, **kwargs):
132 def __init__(self, func_name, **kwargs):
133 self.function_name = func_name
133 self.function_name = func_name
134 self.value = _NA
134 self.value = _NA
135 self.state = None
135 self.state = None
136 self.kwargs = kwargs or {}
136 self.kwargs = kwargs or {}
137
137
138 def __call__(self):
138 def __call__(self):
139 computed = self.compute(**self.kwargs)
139 computed = self.compute(**self.kwargs)
140 if not isinstance(computed, SysInfoRes):
140 if not isinstance(computed, SysInfoRes):
141 raise ValueError(
141 raise ValueError(
142 'computed value for {} is not instance of '
142 'computed value for {} is not instance of '
143 '{}, got {} instead'.format(
143 '{}, got {} instead'.format(
144 self.function_name, SysInfoRes, type(computed)))
144 self.function_name, SysInfoRes, type(computed)))
145 return computed.__json__()
145 return computed.__json__()
146
146
147 def __str__(self):
147 def __str__(self):
148 return f'<SysInfo({self.function_name})>'
148 return f'<SysInfo({self.function_name})>'
149
149
150 def compute(self, **kwargs):
150 def compute(self, **kwargs):
151 return self.function_name(**kwargs)
151 return self.function_name(**kwargs)
152
152
153
153
154 # SysInfo functions
154 # SysInfo functions
155 @register_sysinfo
155 @register_sysinfo
156 def python_info():
156 def python_info():
157 value = dict(version=f'{platform.python_version()}:{platform.python_implementation()}',
157 value = dict(version=f'{platform.python_version()}:{platform.python_implementation()}',
158 executable=sys.executable)
158 executable=sys.executable)
159 return SysInfoRes(value=value)
159 return SysInfoRes(value=value)
160
160
161
161
162 @register_sysinfo
162 @register_sysinfo
163 def py_modules():
163 def py_modules():
164 mods = dict([(p.project_name, {'version': p.version, 'location': p.location})
164 mods = dict([(p.project_name, {'version': p.version, 'location': p.location})
165 for p in pkg_resources.working_set])
165 for p in pkg_resources.working_set])
166
166
167 value = sorted(mods.items(), key=lambda k: k[0].lower())
167 value = sorted(mods.items(), key=lambda k: k[0].lower())
168 return SysInfoRes(value=value)
168 return SysInfoRes(value=value)
169
169
170
170
171 @register_sysinfo
171 @register_sysinfo
172 def platform_type():
172 def platform_type():
173 from rhodecode.lib.utils import generate_platform_uuid
173 from rhodecode.lib.utils import generate_platform_uuid
174
174
175 value = dict(
175 value = dict(
176 name=safe_str(platform.platform()),
176 name=safe_str(platform.platform()),
177 uuid=generate_platform_uuid()
177 uuid=generate_platform_uuid()
178 )
178 )
179 return SysInfoRes(value=value)
179 return SysInfoRes(value=value)
180
180
181
181
182 @register_sysinfo
182 @register_sysinfo
183 def locale_info():
183 def locale_info():
184 import locale
184 import locale
185
185
186 def safe_get_locale(locale_name):
186 def safe_get_locale(locale_name):
187 try:
187 try:
188 locale.getlocale(locale_name)
188 locale.getlocale(locale_name)
189 except TypeError:
189 except TypeError:
190 return f'FAILED_LOCALE_GET:{locale_name}'
190 return f'FAILED_LOCALE_GET:{locale_name}'
191
191
192 value = dict(
192 value = dict(
193 locale_default=locale.getlocale(),
193 locale_default=locale.getlocale(),
194 locale_lc_all=safe_get_locale(locale.LC_ALL),
194 locale_lc_all=safe_get_locale(locale.LC_ALL),
195 locale_lc_ctype=safe_get_locale(locale.LC_CTYPE),
195 locale_lc_ctype=safe_get_locale(locale.LC_CTYPE),
196 lang_env=os.environ.get('LANG'),
196 lang_env=os.environ.get('LANG'),
197 lc_all_env=os.environ.get('LC_ALL'),
197 lc_all_env=os.environ.get('LC_ALL'),
198 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
198 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
199 )
199 )
200 human_value = \
200 human_value = \
201 f"LANG: {value['lang_env']}, \
201 f"LANG: {value['lang_env']}, \
202 locale LC_ALL: {value['locale_lc_all']}, \
202 locale LC_ALL: {value['locale_lc_all']}, \
203 locale LC_CTYPE: {value['locale_lc_ctype']}, \
203 locale LC_CTYPE: {value['locale_lc_ctype']}, \
204 Default locales: {value['locale_default']}"
204 Default locales: {value['locale_default']}"
205
205
206 return SysInfoRes(value=value, human_value=human_value)
206 return SysInfoRes(value=value, human_value=human_value)
207
207
208
208
209 @register_sysinfo
209 @register_sysinfo
210 def ulimit_info():
210 def ulimit_info():
211 data = collections.OrderedDict([
211 data = collections.OrderedDict([
212 ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)),
212 ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)),
213 ('file size', get_resource(resource.RLIMIT_FSIZE)),
213 ('file size', get_resource(resource.RLIMIT_FSIZE)),
214 ('stack size', get_resource(resource.RLIMIT_STACK)),
214 ('stack size', get_resource(resource.RLIMIT_STACK)),
215 ('core file size', get_resource(resource.RLIMIT_CORE)),
215 ('core file size', get_resource(resource.RLIMIT_CORE)),
216 ('address space size', get_resource(resource.RLIMIT_AS)),
216 ('address space size', get_resource(resource.RLIMIT_AS)),
217 ('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)),
217 ('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)),
218 ('heap size', get_resource(resource.RLIMIT_DATA)),
218 ('heap size', get_resource(resource.RLIMIT_DATA)),
219 ('rss size', get_resource(resource.RLIMIT_RSS)),
219 ('rss size', get_resource(resource.RLIMIT_RSS)),
220 ('number of processes', get_resource(resource.RLIMIT_NPROC)),
220 ('number of processes', get_resource(resource.RLIMIT_NPROC)),
221 ('open files', get_resource(resource.RLIMIT_NOFILE)),
221 ('open files', get_resource(resource.RLIMIT_NOFILE)),
222 ])
222 ])
223
223
224 text = ', '.join(f'{k}:{v}' for k, v in data.items())
224 text = ', '.join(f'{k}:{v}' for k, v in data.items())
225
225
226 value = {
226 value = {
227 'limits': data,
227 'limits': data,
228 'text': text,
228 'text': text,
229 }
229 }
230 return SysInfoRes(value=value)
230 return SysInfoRes(value=value)
231
231
232
232
233 @register_sysinfo
233 @register_sysinfo
234 def uptime():
234 def uptime():
235 from rhodecode.lib.helpers import age, time_to_datetime
235 from rhodecode.lib.helpers import age, time_to_datetime
236 from rhodecode.translation import TranslationString
236 from rhodecode.translation import TranslationString
237
237
238 value = dict(boot_time=0, uptime=0, text='')
238 value = dict(boot_time=0, uptime=0, text='')
239 state = STATE_OK_DEFAULT
239 state = STATE_OK_DEFAULT
240
240
241 boot_time = psutil.boot_time()
241 boot_time = psutil.boot_time()
242 value['boot_time'] = boot_time
242 value['boot_time'] = boot_time
243 value['uptime'] = time.time() - boot_time
243 value['uptime'] = time.time() - boot_time
244
244
245 date_or_age = age(time_to_datetime(boot_time))
245 date_or_age = age(time_to_datetime(boot_time))
246 if isinstance(date_or_age, TranslationString):
246 if isinstance(date_or_age, TranslationString):
247 date_or_age = date_or_age.interpolate()
247 date_or_age = date_or_age.interpolate()
248
248
249 human_value = value.copy()
249 human_value = value.copy()
250 human_value['boot_time'] = time_to_datetime(boot_time)
250 human_value['boot_time'] = time_to_datetime(boot_time)
251 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
251 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
252
252
253 human_value['text'] = f'Server started {date_or_age}'
253 human_value['text'] = f'Server started {date_or_age}'
254 return SysInfoRes(value=value, human_value=human_value)
254 return SysInfoRes(value=value, human_value=human_value)
255
255
256
256
257 @register_sysinfo
257 @register_sysinfo
258 def memory():
258 def memory():
259 from rhodecode.lib.helpers import format_byte_size_binary
259 from rhodecode.lib.helpers import format_byte_size_binary
260 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
260 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
261 percent_used=0, free=0, inactive=0, active=0, shared=0,
261 percent_used=0, free=0, inactive=0, active=0, shared=0,
262 total=0, buffers=0, text='')
262 total=0, buffers=0, text='')
263
263
264 state = STATE_OK_DEFAULT
264 state = STATE_OK_DEFAULT
265
265
266 value.update(dict(psutil.virtual_memory()._asdict()))
266 value.update(dict(psutil.virtual_memory()._asdict()))
267 value['used_real'] = value['total'] - value['available']
267 value['used_real'] = value['total'] - value['available']
268 value['percent_used'] = psutil._common.usage_percent(value['used_real'], value['total'], 1)
268 value['percent_used'] = psutil._common.usage_percent(value['used_real'], value['total'], 1)
269
269
270 human_value = value.copy()
270 human_value = value.copy()
271 human_value['text'] = '{}/{}, {}% used'.format(
271 human_value['text'] = '{}/{}, {}% used'.format(
272 format_byte_size_binary(value['used_real']),
272 format_byte_size_binary(value['used_real']),
273 format_byte_size_binary(value['total']),
273 format_byte_size_binary(value['total']),
274 value['percent_used'])
274 value['percent_used'])
275
275
276 keys = list(value.keys())[::]
276 keys = list(value.keys())[::]
277 keys.pop(keys.index('percent'))
277 keys.pop(keys.index('percent'))
278 keys.pop(keys.index('percent_used'))
278 keys.pop(keys.index('percent_used'))
279 keys.pop(keys.index('text'))
279 keys.pop(keys.index('text'))
280 for k in keys:
280 for k in keys:
281 human_value[k] = format_byte_size_binary(value[k])
281 human_value[k] = format_byte_size_binary(value[k])
282
282
283 if state['type'] == STATE_OK and value['percent_used'] > 90:
283 if state['type'] == STATE_OK and value['percent_used'] > 90:
284 msg = 'Critical: your available RAM memory is very low.'
284 msg = 'Critical: your available RAM memory is very low.'
285 state = {'message': msg, 'type': STATE_ERR}
285 state = {'message': msg, 'type': STATE_ERR}
286
286
287 elif state['type'] == STATE_OK and value['percent_used'] > 70:
287 elif state['type'] == STATE_OK and value['percent_used'] > 70:
288 msg = 'Warning: your available RAM memory is running low.'
288 msg = 'Warning: your available RAM memory is running low.'
289 state = {'message': msg, 'type': STATE_WARN}
289 state = {'message': msg, 'type': STATE_WARN}
290
290
291 return SysInfoRes(value=value, state=state, human_value=human_value)
291 return SysInfoRes(value=value, state=state, human_value=human_value)
292
292
293
293
294 @register_sysinfo
294 @register_sysinfo
295 def machine_load():
295 def machine_load():
296 value = {'1_min': _NA_FLOAT, '5_min': _NA_FLOAT, '15_min': _NA_FLOAT, 'text': ''}
296 value = {'1_min': _NA_FLOAT, '5_min': _NA_FLOAT, '15_min': _NA_FLOAT, 'text': ''}
297 state = STATE_OK_DEFAULT
297 state = STATE_OK_DEFAULT
298
298
299 # load averages
299 # load averages
300 if hasattr(psutil.os, 'getloadavg'):
300 if hasattr(psutil.os, 'getloadavg'):
301 value.update(dict(
301 value.update(dict(
302 list(zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg()))
302 list(zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg()))
303 ))
303 ))
304
304
305 human_value = value.copy()
305 human_value = value.copy()
306 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
306 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
307 value['1_min'], value['5_min'], value['15_min'])
307 value['1_min'], value['5_min'], value['15_min'])
308
308
309 if state['type'] == STATE_OK and value['15_min'] > 5.0:
309 if state['type'] == STATE_OK and value['15_min'] > 5.0:
310 msg = 'Warning: your machine load is very high.'
310 msg = 'Warning: your machine load is very high.'
311 state = {'message': msg, 'type': STATE_WARN}
311 state = {'message': msg, 'type': STATE_WARN}
312
312
313 return SysInfoRes(value=value, state=state, human_value=human_value)
313 return SysInfoRes(value=value, state=state, human_value=human_value)
314
314
315
315
316 @register_sysinfo
316 @register_sysinfo
317 def cpu():
317 def cpu():
318 value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []}
318 value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []}
319 state = STATE_OK_DEFAULT
319 state = STATE_OK_DEFAULT
320
320
321 value['cpu'] = psutil.cpu_percent(0.5)
321 value['cpu'] = psutil.cpu_percent(0.5)
322 value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True)
322 value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True)
323 value['cpu_count'] = psutil.cpu_count()
323 value['cpu_count'] = psutil.cpu_count()
324
324
325 human_value = value.copy()
325 human_value = value.copy()
326 human_value['text'] = f'{value["cpu_count"]} cores at {value["cpu"]} %'
326 human_value['text'] = f'{value["cpu_count"]} cores at {value["cpu"]} %'
327
327
328 return SysInfoRes(value=value, state=state, human_value=human_value)
328 return SysInfoRes(value=value, state=state, human_value=human_value)
329
329
330
330
331 @register_sysinfo
331 @register_sysinfo
332 def storage():
332 def storage():
333 from rhodecode.lib.helpers import format_byte_size_binary
333 from rhodecode.lib.helpers import format_byte_size_binary
334 from rhodecode.lib.utils import get_rhodecode_repo_store_path
334 from rhodecode.lib.utils import get_rhodecode_repo_store_path
335 path = get_rhodecode_repo_store_path()
335 path = get_rhodecode_repo_store_path()
336
336
337 value = dict(percent=0, used=0, total=0, path=path, text='')
337 value = dict(percent=0, used=0, total=0, path=path, text='')
338 state = STATE_OK_DEFAULT
338 state = STATE_OK_DEFAULT
339
339
340 try:
340 try:
341 value.update(dict(psutil.disk_usage(path)._asdict()))
341 value.update(dict(psutil.disk_usage(path)._asdict()))
342 except Exception as e:
342 except Exception as e:
343 log.exception('Failed to fetch disk info')
343 log.exception('Failed to fetch disk info')
344 state = {'message': str(e), 'type': STATE_ERR}
344 state = {'message': str(e), 'type': STATE_ERR}
345
345
346 human_value = value.copy()
346 human_value = value.copy()
347 human_value['used'] = format_byte_size_binary(value['used'])
347 human_value['used'] = format_byte_size_binary(value['used'])
348 human_value['total'] = format_byte_size_binary(value['total'])
348 human_value['total'] = format_byte_size_binary(value['total'])
349 human_value['text'] = "{}/{}, {}% used".format(
349 human_value['text'] = "{}/{}, {}% used".format(
350 format_byte_size_binary(value['used']),
350 format_byte_size_binary(value['used']),
351 format_byte_size_binary(value['total']),
351 format_byte_size_binary(value['total']),
352 value['percent'])
352 value['percent'])
353
353
354 if state['type'] == STATE_OK and value['percent'] > 90:
354 if state['type'] == STATE_OK and value['percent'] > 90:
355 msg = 'Critical: your disk space is very low.'
355 msg = 'Critical: your disk space is very low.'
356 state = {'message': msg, 'type': STATE_ERR}
356 state = {'message': msg, 'type': STATE_ERR}
357
357
358 elif state['type'] == STATE_OK and value['percent'] > 70:
358 elif state['type'] == STATE_OK and value['percent'] > 70:
359 msg = 'Warning: your disk space is running low.'
359 msg = 'Warning: your disk space is running low.'
360 state = {'message': msg, 'type': STATE_WARN}
360 state = {'message': msg, 'type': STATE_WARN}
361
361
362 return SysInfoRes(value=value, state=state, human_value=human_value)
362 return SysInfoRes(value=value, state=state, human_value=human_value)
363
363
364
364
365 @register_sysinfo
365 @register_sysinfo
366 def storage_inodes():
366 def storage_inodes():
367 from rhodecode.lib.utils import get_rhodecode_repo_store_path
367 from rhodecode.lib.utils import get_rhodecode_repo_store_path
368 path = get_rhodecode_repo_store_path()
368 path = get_rhodecode_repo_store_path()
369
369
370 value = dict(percent=0.0, free=0, used=0, total=0, path=path, text='')
370 value = dict(percent=0.0, free=0, used=0, total=0, path=path, text='')
371 state = STATE_OK_DEFAULT
371 state = STATE_OK_DEFAULT
372
372
373 try:
373 try:
374 i_stat = os.statvfs(path)
374 i_stat = os.statvfs(path)
375 value['free'] = i_stat.f_ffree
375 value['free'] = i_stat.f_ffree
376 value['used'] = i_stat.f_files-i_stat.f_favail
376 value['used'] = i_stat.f_files-i_stat.f_favail
377 value['total'] = i_stat.f_files
377 value['total'] = i_stat.f_files
378 value['percent'] = percentage(value['used'], value['total'])
378 value['percent'] = percentage(value['used'], value['total'])
379 except Exception as e:
379 except Exception as e:
380 log.exception('Failed to fetch disk inodes info')
380 log.exception('Failed to fetch disk inodes info')
381 state = {'message': str(e), 'type': STATE_ERR}
381 state = {'message': str(e), 'type': STATE_ERR}
382
382
383 human_value = value.copy()
383 human_value = value.copy()
384 human_value['text'] = "{}/{}, {}% used".format(
384 human_value['text'] = "{}/{}, {}% used".format(
385 value['used'], value['total'], value['percent'])
385 value['used'], value['total'], value['percent'])
386
386
387 if state['type'] == STATE_OK and value['percent'] > 90:
387 if state['type'] == STATE_OK and value['percent'] > 90:
388 msg = 'Critical: your disk free inodes are very low.'
388 msg = 'Critical: your disk free inodes are very low.'
389 state = {'message': msg, 'type': STATE_ERR}
389 state = {'message': msg, 'type': STATE_ERR}
390
390
391 elif state['type'] == STATE_OK and value['percent'] > 70:
391 elif state['type'] == STATE_OK and value['percent'] > 70:
392 msg = 'Warning: your disk free inodes are running low.'
392 msg = 'Warning: your disk free inodes are running low.'
393 state = {'message': msg, 'type': STATE_WARN}
393 state = {'message': msg, 'type': STATE_WARN}
394
394
395 return SysInfoRes(value=value, state=state, human_value=human_value)
395 return SysInfoRes(value=value, state=state, human_value=human_value)
396
396
397
397
398 @register_sysinfo
398 @register_sysinfo
399 def storage_artifacts():
399 def storage_artifacts():
400 import rhodecode
400 import rhodecode
401 from rhodecode.lib.helpers import format_byte_size_binary
401 from rhodecode.lib.helpers import format_byte_size_binary
402 from rhodecode.lib.archive_cache import get_archival_cache_store
402 from rhodecode.lib.archive_cache import get_archival_cache_store
403
403
404 backend_type = rhodecode.ConfigGet().get_str('archive_cache.backend.type')
404 backend_type = rhodecode.ConfigGet().get_str('archive_cache.backend.type')
405
405
406 value = dict(percent=0, used=0, total=0, items=0, path='', text='', type=backend_type)
406 value = dict(percent=0, used=0, total=0, items=0, path='', text='', type=backend_type)
407 state = STATE_OK_DEFAULT
407 state = STATE_OK_DEFAULT
408 try:
408 try:
409 d_cache = get_archival_cache_store(config=rhodecode.CONFIG)
409 d_cache = get_archival_cache_store(config=rhodecode.CONFIG)
410 backend_type = str(d_cache)
410 backend_type = str(d_cache)
411
411
412 total_files, total_size, _directory_stats = d_cache.get_statistics()
412 total_files, total_size, _directory_stats = d_cache.get_statistics()
413
413
414 value.update({
414 value.update({
415 'percent': 100,
415 'percent': 100,
416 'used': total_size,
416 'used': total_size,
417 'total': total_size,
417 'total': total_size,
418 'items': total_files,
418 'items': total_files,
419 'path': d_cache.storage_path,
419 'path': d_cache.storage_path,
420 'type': backend_type
420 'type': backend_type
421 })
421 })
422
422
423 except Exception as e:
423 except Exception as e:
424 log.exception('failed to fetch archive cache storage')
424 log.exception('failed to fetch archive cache storage')
425 state = {'message': str(e), 'type': STATE_ERR}
425 state = {'message': str(e), 'type': STATE_ERR}
426
426
427 human_value = value.copy()
427 human_value = value.copy()
428 human_value['used'] = format_byte_size_binary(value['used'])
428 human_value['used'] = format_byte_size_binary(value['used'])
429 human_value['total'] = format_byte_size_binary(value['total'])
429 human_value['total'] = format_byte_size_binary(value['total'])
430 human_value['text'] = f"{human_value['used']} ({value['items']} items)"
430 human_value['text'] = f"{human_value['used']} ({value['items']} items)"
431
431
432 return SysInfoRes(value=value, state=state, human_value=human_value)
432 return SysInfoRes(value=value, state=state, human_value=human_value)
433
433
434
434
435 @register_sysinfo
435 @register_sysinfo
436 def storage_archives():
436 def storage_archives():
437 import rhodecode
437 import rhodecode
438 from rhodecode.lib.helpers import format_byte_size_binary
438 from rhodecode.lib.helpers import format_byte_size_binary
439 import rhodecode.apps.file_store.utils as store_utils
439 import rhodecode.apps.file_store.utils as store_utils
440 from rhodecode import CONFIG
440 from rhodecode import CONFIG
441
441
442 backend_type = rhodecode.ConfigGet().get_str(store_utils.config_keys.backend_type)
442 backend_type = rhodecode.ConfigGet().get_str(store_utils.config_keys.backend_type)
443
443
444 value = dict(percent=0, used=0, total=0, items=0, path='', text='', type=backend_type)
444 value = dict(percent=0, used=0, total=0, items=0, path='', text='', type=backend_type)
445 state = STATE_OK_DEFAULT
445 state = STATE_OK_DEFAULT
446 try:
446 try:
447 f_store = store_utils.get_filestore_backend(config=CONFIG)
447 f_store = store_utils.get_filestore_backend(config=CONFIG)
448 backend_type = str(f_store)
448 backend_type = str(f_store)
449 total_files, total_size, _directory_stats = f_store.get_statistics()
449 total_files, total_size, _directory_stats = f_store.get_statistics()
450
450
451 value.update({
451 value.update({
452 'percent': 100,
452 'percent': 100,
453 'used': total_size,
453 'used': total_size,
454 'total': total_size,
454 'total': total_size,
455 'items': total_files,
455 'items': total_files,
456 'path': f_store.storage_path,
456 'path': f_store.storage_path,
457 'type': backend_type
457 'type': backend_type
458 })
458 })
459
459
460 except Exception as e:
460 except Exception as e:
461 log.exception('failed to fetch archive cache storage')
461 log.exception('failed to fetch archive cache storage')
462 state = {'message': str(e), 'type': STATE_ERR}
462 state = {'message': str(e), 'type': STATE_ERR}
463
463
464 human_value = value.copy()
464 human_value = value.copy()
465 human_value['used'] = format_byte_size_binary(value['used'])
465 human_value['used'] = format_byte_size_binary(value['used'])
466 human_value['total'] = format_byte_size_binary(value['total'])
466 human_value['total'] = format_byte_size_binary(value['total'])
467 human_value['text'] = f"{human_value['used']} ({value['items']} items)"
467 human_value['text'] = f"{human_value['used']} ({value['items']} items)"
468
468
469 return SysInfoRes(value=value, state=state, human_value=human_value)
469 return SysInfoRes(value=value, state=state, human_value=human_value)
470
470
471
471
472 @register_sysinfo
472 @register_sysinfo
473 def storage_gist():
473 def storage_gist():
474 from rhodecode.model.gist import GIST_STORE_LOC
474 from rhodecode.model.gist import GIST_STORE_LOC
475 from rhodecode.lib.utils import safe_str, get_rhodecode_repo_store_path
475 from rhodecode.lib.utils import safe_str, get_rhodecode_repo_store_path
476 from rhodecode.lib.helpers import format_byte_size_binary, get_directory_statistics
476 from rhodecode.lib.helpers import format_byte_size_binary, get_directory_statistics
477
477
478 path = safe_str(os.path.join(
478 path = safe_str(os.path.join(
479 get_rhodecode_repo_store_path(), GIST_STORE_LOC))
479 get_rhodecode_repo_store_path(), GIST_STORE_LOC))
480
480
481 # gist storage
481 # gist storage
482 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
482 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
483 state = STATE_OK_DEFAULT
483 state = STATE_OK_DEFAULT
484
484
485 try:
485 try:
486 total_files, total_size, _directory_stats = get_directory_statistics(path)
486 total_files, total_size, _directory_stats = get_directory_statistics(path)
487 value.update({
487 value.update({
488 'percent': 100,
488 'percent': 100,
489 'used': total_size,
489 'used': total_size,
490 'total': total_size,
490 'total': total_size,
491 'items': total_files
491 'items': total_files
492 })
492 })
493 except Exception as e:
493 except Exception as e:
494 log.exception('failed to fetch gist storage items')
494 log.exception('failed to fetch gist storage items')
495 state = {'message': str(e), 'type': STATE_ERR}
495 state = {'message': str(e), 'type': STATE_ERR}
496
496
497 human_value = value.copy()
497 human_value = value.copy()
498 human_value['used'] = format_byte_size_binary(value['used'])
498 human_value['used'] = format_byte_size_binary(value['used'])
499 human_value['total'] = format_byte_size_binary(value['total'])
499 human_value['total'] = format_byte_size_binary(value['total'])
500 human_value['text'] = "{} ({} items)".format(
500 human_value['text'] = "{} ({} items)".format(
501 human_value['used'], value['items'])
501 human_value['used'], value['items'])
502
502
503 return SysInfoRes(value=value, state=state, human_value=human_value)
503 return SysInfoRes(value=value, state=state, human_value=human_value)
504
504
505
505
506 @register_sysinfo
506 @register_sysinfo
507 def storage_temp():
507 def storage_temp():
508 import tempfile
508 import tempfile
509 from rhodecode.lib.helpers import format_byte_size_binary
509 from rhodecode.lib.helpers import format_byte_size_binary
510
510
511 path = tempfile.gettempdir()
511 path = tempfile.gettempdir()
512 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
512 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
513 state = STATE_OK_DEFAULT
513 state = STATE_OK_DEFAULT
514
514
515 if not psutil:
515 if not psutil:
516 return SysInfoRes(value=value, state=state)
516 return SysInfoRes(value=value, state=state)
517
517
518 try:
518 try:
519 value.update(dict(psutil.disk_usage(path)._asdict()))
519 value.update(dict(psutil.disk_usage(path)._asdict()))
520 except Exception as e:
520 except Exception as e:
521 log.exception('Failed to fetch temp dir info')
521 log.exception('Failed to fetch temp dir info')
522 state = {'message': str(e), 'type': STATE_ERR}
522 state = {'message': str(e), 'type': STATE_ERR}
523
523
524 human_value = value.copy()
524 human_value = value.copy()
525 human_value['used'] = format_byte_size_binary(value['used'])
525 human_value['used'] = format_byte_size_binary(value['used'])
526 human_value['total'] = format_byte_size_binary(value['total'])
526 human_value['total'] = format_byte_size_binary(value['total'])
527 human_value['text'] = "{}/{}, {}% used".format(
527 human_value['text'] = "{}/{}, {}% used".format(
528 format_byte_size_binary(value['used']),
528 format_byte_size_binary(value['used']),
529 format_byte_size_binary(value['total']),
529 format_byte_size_binary(value['total']),
530 value['percent'])
530 value['percent'])
531
531
532 return SysInfoRes(value=value, state=state, human_value=human_value)
532 return SysInfoRes(value=value, state=state, human_value=human_value)
533
533
534
534
535 @register_sysinfo
535 @register_sysinfo
536 def search_info():
536 def search_info():
537 import rhodecode
537 import rhodecode
538 from rhodecode.lib.index import searcher_from_config
538 from rhodecode.lib.index import searcher_from_config
539
539
540 backend = rhodecode.CONFIG.get('search.module', '')
540 backend = rhodecode.CONFIG.get('search.module', '')
541 location = rhodecode.CONFIG.get('search.location', '')
541 location = rhodecode.CONFIG.get('search.location', '')
542
542
543 try:
543 try:
544 searcher = searcher_from_config(rhodecode.CONFIG)
544 searcher = searcher_from_config(rhodecode.CONFIG)
545 searcher = searcher.__class__.__name__
545 searcher = searcher.__class__.__name__
546 except Exception:
546 except Exception:
547 searcher = None
547 searcher = None
548
548
549 value = dict(
549 value = dict(
550 backend=backend, searcher=searcher, location=location, text='')
550 backend=backend, searcher=searcher, location=location, text='')
551 state = STATE_OK_DEFAULT
551 state = STATE_OK_DEFAULT
552
552
553 human_value = value.copy()
553 human_value = value.copy()
554 human_value['text'] = "backend:`{}`".format(human_value['backend'])
554 human_value['text'] = "backend:`{}`".format(human_value['backend'])
555
555
556 return SysInfoRes(value=value, state=state, human_value=human_value)
556 return SysInfoRes(value=value, state=state, human_value=human_value)
557
557
558
558
559 @register_sysinfo
559 @register_sysinfo
560 def git_info():
560 def git_info():
561 from rhodecode.lib.vcs.backends import git
561 from rhodecode.lib.vcs.backends import git
562 state = STATE_OK_DEFAULT
562 state = STATE_OK_DEFAULT
563 value = human_value = ''
563 value = human_value = ''
564 try:
564 try:
565 value = git.discover_git_version(raise_on_exc=True)
565 value = git.discover_git_version(raise_on_exc=True)
566 human_value = f'version reported from VCSServer: {value}'
566 human_value = f'version reported from VCSServer: {value}'
567 except Exception as e:
567 except Exception as e:
568 state = {'message': str(e), 'type': STATE_ERR}
568 state = {'message': str(e), 'type': STATE_ERR}
569
569
570 return SysInfoRes(value=value, state=state, human_value=human_value)
570 return SysInfoRes(value=value, state=state, human_value=human_value)
571
571
572
572
573 @register_sysinfo
573 @register_sysinfo
574 def hg_info():
574 def hg_info():
575 from rhodecode.lib.vcs.backends import hg
575 from rhodecode.lib.vcs.backends import hg
576 state = STATE_OK_DEFAULT
576 state = STATE_OK_DEFAULT
577 value = human_value = ''
577 value = human_value = ''
578 try:
578 try:
579 value = hg.discover_hg_version(raise_on_exc=True)
579 value = hg.discover_hg_version(raise_on_exc=True)
580 human_value = f'version reported from VCSServer: {value}'
580 human_value = f'version reported from VCSServer: {value}'
581 except Exception as e:
581 except Exception as e:
582 state = {'message': str(e), 'type': STATE_ERR}
582 state = {'message': str(e), 'type': STATE_ERR}
583 return SysInfoRes(value=value, state=state, human_value=human_value)
583 return SysInfoRes(value=value, state=state, human_value=human_value)
584
584
585
585
586 @register_sysinfo
586 @register_sysinfo
587 def svn_info():
587 def svn_info():
588 from rhodecode.lib.vcs.backends import svn
588 from rhodecode.lib.vcs.backends import svn
589 state = STATE_OK_DEFAULT
589 state = STATE_OK_DEFAULT
590 value = human_value = ''
590 value = human_value = ''
591 try:
591 try:
592 value = svn.discover_svn_version(raise_on_exc=True)
592 value = svn.discover_svn_version(raise_on_exc=True)
593 human_value = f'version reported from VCSServer: {value}'
593 human_value = f'version reported from VCSServer: {value}'
594 except Exception as e:
594 except Exception as e:
595 state = {'message': str(e), 'type': STATE_ERR}
595 state = {'message': str(e), 'type': STATE_ERR}
596 return SysInfoRes(value=value, state=state, human_value=human_value)
596 return SysInfoRes(value=value, state=state, human_value=human_value)
597
597
598
598
599 @register_sysinfo
599 @register_sysinfo
600 def vcs_backends():
600 def vcs_backends():
601 import rhodecode
601 import rhodecode
602 value = rhodecode.CONFIG.get('vcs.backends')
602 value = rhodecode.CONFIG.get('vcs.backends')
603 human_value = 'Enabled backends in order: {}'.format(','.join(value))
603 human_value = 'Enabled backends in order: {}'.format(','.join(value))
604 return SysInfoRes(value=value, human_value=human_value)
604 return SysInfoRes(value=value, human_value=human_value)
605
605
606
606
607 @register_sysinfo
607 @register_sysinfo
608 def vcs_server():
608 def vcs_server():
609 import rhodecode
609 import rhodecode
610 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
610 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
611
611
612 server_url = rhodecode.CONFIG.get('vcs.server')
612 server_url = rhodecode.CONFIG.get('vcs.server')
613 enabled = rhodecode.CONFIG.get('vcs.server.enable')
613 enabled = rhodecode.CONFIG.get('vcs.server.enable')
614 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
614 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
615 state = STATE_OK_DEFAULT
615 state = STATE_OK_DEFAULT
616 version = None
616 version = None
617 workers = 0
617 workers = 0
618
618
619 try:
619 try:
620 data = get_vcsserver_service_data()
620 data = get_vcsserver_service_data()
621 if data and 'version' in data:
621 if data and 'version' in data:
622 version = data['version']
622 version = data['version']
623
623
624 if data and 'config' in data:
624 if data and 'config' in data:
625 conf = data['config']
625 conf = data['config']
626 workers = conf.get('workers', 'NOT AVAILABLE')
626 workers = conf.get('workers', 'NOT AVAILABLE')
627
627
628 connection = 'connected'
628 connection = 'connected'
629 except Exception as e:
629 except Exception as e:
630 connection = 'failed'
630 connection = 'failed'
631 state = {'message': str(e), 'type': STATE_ERR}
631 state = {'message': str(e), 'type': STATE_ERR}
632
632
633 value = dict(
633 value = dict(
634 url=server_url,
634 url=server_url,
635 enabled=enabled,
635 enabled=enabled,
636 protocol=protocol,
636 protocol=protocol,
637 connection=connection,
637 connection=connection,
638 version=version,
638 version=version,
639 text='',
639 text='',
640 )
640 )
641
641
642 human_value = value.copy()
642 human_value = value.copy()
643 human_value['text'] = \
643 human_value['text'] = \
644 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
644 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
645 url=server_url, ver=version, workers=workers, mode=protocol,
645 url=server_url, ver=version, workers=workers, mode=protocol,
646 conn=connection)
646 conn=connection)
647
647
648 return SysInfoRes(value=value, state=state, human_value=human_value)
648 return SysInfoRes(value=value, state=state, human_value=human_value)
649
649
650
650
651 @register_sysinfo
651 @register_sysinfo
652 def vcs_server_config():
652 def vcs_server_config():
653 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
653 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
654 state = STATE_OK_DEFAULT
654 state = STATE_OK_DEFAULT
655
655
656 value = {}
656 value = {}
657 try:
657 try:
658 data = get_vcsserver_service_data()
658 data = get_vcsserver_service_data()
659 value = data['app_config']
659 value = data['app_config']
660 except Exception as e:
660 except Exception as e:
661 state = {'message': str(e), 'type': STATE_ERR}
661 state = {'message': str(e), 'type': STATE_ERR}
662
662
663 human_value = value.copy()
663 human_value = value.copy()
664 human_value['text'] = 'VCS Server config'
664 human_value['text'] = 'VCS Server config'
665
665
666 return SysInfoRes(value=value, state=state, human_value=human_value)
666 return SysInfoRes(value=value, state=state, human_value=human_value)
667
667
668 @register_sysinfo
669 def rhodecode_server_config():
670 import rhodecode
671
672 state = STATE_OK_DEFAULT
673 config = rhodecode.CONFIG.copy()
674
675 secrets_lits = [
676 f'rhodecode_{LicenseModel.LICENSE_DB_KEY}',
677 'sqlalchemy.db1.url',
678 'channelstream.secret',
679 'beaker.session.secret',
680 'rhodecode.encrypted_values.secret',
681 'appenlight.api_key',
682 'smtp_password',
683 'file_store.objectstore.secret',
684 'archive_cache.objectstore.secret',
685 'app.service_api.token',
686 ]
687 for k in secrets_lits:
688 if k in config:
689 config[k] = '**OBFUSCATED**'
690
691 value = human_value = config
692 return SysInfoRes(value=value, state=state, human_value=human_value)
693
668
694
669 @register_sysinfo
695 @register_sysinfo
670 def rhodecode_app_info():
696 def rhodecode_app_info():
671 import rhodecode
697 import rhodecode
672 edition = rhodecode.CONFIG.get('rhodecode.edition')
698 edition = rhodecode.CONFIG.get('rhodecode.edition')
673
699
674 value = dict(
700 value = dict(
675 rhodecode_version=rhodecode.__version__,
701 rhodecode_version=rhodecode.__version__,
676 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
702 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
677 text=''
703 text=''
678 )
704 )
679 human_value = value.copy()
705 human_value = value.copy()
680 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
706 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
681 edition=edition, ver=value['rhodecode_version']
707 edition=edition, ver=value['rhodecode_version']
682 )
708 )
683 return SysInfoRes(value=value, human_value=human_value)
709 return SysInfoRes(value=value, human_value=human_value)
684
710
685
711
686 @register_sysinfo
712 @register_sysinfo
687 def rhodecode_config():
713 def rhodecode_config():
688 import rhodecode
714 import rhodecode
689 path = rhodecode.CONFIG.get('__file__')
715 path = rhodecode.CONFIG.get('__file__')
690 rhodecode_ini_safe = rhodecode.CONFIG.copy()
716 rhodecode_ini_safe = rhodecode.CONFIG.copy()
691 cert_path = get_cert_path(path)
717 cert_path = get_cert_path(path)
692
718
693 try:
719 try:
694 config = configparser.ConfigParser()
720 config = configparser.ConfigParser()
695 config.read(path)
721 config.read(path)
696 parsed_ini = config
722 parsed_ini = config
697 if parsed_ini.has_section('server:main'):
723 if parsed_ini.has_section('server:main'):
698 parsed_ini = dict(parsed_ini.items('server:main'))
724 parsed_ini = dict(parsed_ini.items('server:main'))
699 except Exception:
725 except Exception:
700 log.exception('Failed to read .ini file for display')
726 log.exception('Failed to read .ini file for display')
701 parsed_ini = {}
727 parsed_ini = {}
702
728
703 rhodecode_ini_safe['server:main'] = parsed_ini
729 rhodecode_ini_safe['server:main'] = parsed_ini
704
730
705 blacklist = [
731 blacklist = [
706 f'rhodecode_{LicenseModel.LICENSE_DB_KEY}',
732 f'rhodecode_{LicenseModel.LICENSE_DB_KEY}',
707 'routes.map',
733 'routes.map',
708 'sqlalchemy.db1.url',
734 'sqlalchemy.db1.url',
709 'channelstream.secret',
735 'channelstream.secret',
710 'beaker.session.secret',
736 'beaker.session.secret',
711 'rhodecode.encrypted_values.secret',
737 'rhodecode.encrypted_values.secret',
712 'rhodecode_auth_github_consumer_key',
738 'rhodecode_auth_github_consumer_key',
713 'rhodecode_auth_github_consumer_secret',
739 'rhodecode_auth_github_consumer_secret',
714 'rhodecode_auth_google_consumer_key',
740 'rhodecode_auth_google_consumer_key',
715 'rhodecode_auth_google_consumer_secret',
741 'rhodecode_auth_google_consumer_secret',
716 'rhodecode_auth_bitbucket_consumer_secret',
742 'rhodecode_auth_bitbucket_consumer_secret',
717 'rhodecode_auth_bitbucket_consumer_key',
743 'rhodecode_auth_bitbucket_consumer_key',
718 'rhodecode_auth_twitter_consumer_secret',
744 'rhodecode_auth_twitter_consumer_secret',
719 'rhodecode_auth_twitter_consumer_key',
745 'rhodecode_auth_twitter_consumer_key',
720
746
721 'rhodecode_auth_twitter_secret',
747 'rhodecode_auth_twitter_secret',
722 'rhodecode_auth_github_secret',
748 'rhodecode_auth_github_secret',
723 'rhodecode_auth_google_secret',
749 'rhodecode_auth_google_secret',
724 'rhodecode_auth_bitbucket_secret',
750 'rhodecode_auth_bitbucket_secret',
725
751
726 'appenlight.api_key',
752 'appenlight.api_key',
727 ('app_conf', 'sqlalchemy.db1.url')
753 ('app_conf', 'sqlalchemy.db1.url')
728 ]
754 ]
729 for k in blacklist:
755 for k in blacklist:
730 if isinstance(k, tuple):
756 if isinstance(k, tuple):
731 section, key = k
757 section, key = k
732 if section in rhodecode_ini_safe:
758 if section in rhodecode_ini_safe:
733 rhodecode_ini_safe[section] = '**OBFUSCATED**'
759 rhodecode_ini_safe[section] = '**OBFUSCATED**'
734 else:
760 else:
735 rhodecode_ini_safe.pop(k, None)
761 rhodecode_ini_safe.pop(k, None)
736
762
737 # TODO: maybe put some CONFIG checks here ?
763 # TODO: maybe put some CONFIG checks here ?
738 return SysInfoRes(value={'config': rhodecode_ini_safe,
764 return SysInfoRes(value={'config': rhodecode_ini_safe,
739 'path': path, 'cert_path': cert_path})
765 'path': path, 'cert_path': cert_path})
740
766
741
767
742 @register_sysinfo
768 @register_sysinfo
743 def database_info():
769 def database_info():
744 import rhodecode
770 import rhodecode
745 from sqlalchemy.engine import url as engine_url
771 from sqlalchemy.engine import url as engine_url
746 from rhodecode.model import meta
772 from rhodecode.model import meta
747 from rhodecode.model.meta import Session
773 from rhodecode.model.meta import Session
748 from rhodecode.model.db import DbMigrateVersion
774 from rhodecode.model.db import DbMigrateVersion
749
775
750 state = STATE_OK_DEFAULT
776 state = STATE_OK_DEFAULT
751
777
752 db_migrate = DbMigrateVersion.query().filter(
778 db_migrate = DbMigrateVersion.query().filter(
753 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
779 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
754
780
755 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
781 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
756
782
757 try:
783 try:
758 engine = meta.get_engine()
784 engine = meta.get_engine()
759 db_server_info = engine.dialect._get_server_version_info(
785 db_server_info = engine.dialect._get_server_version_info(
760 Session.connection(bind=engine))
786 Session.connection(bind=engine))
761 db_version = '.'.join(map(str, db_server_info))
787 db_version = '.'.join(map(str, db_server_info))
762 except Exception:
788 except Exception:
763 log.exception('failed to fetch db version')
789 log.exception('failed to fetch db version')
764 db_version = 'UNKNOWN'
790 db_version = 'UNKNOWN'
765
791
766 db_info = dict(
792 db_info = dict(
767 migrate_version=db_migrate.version,
793 migrate_version=db_migrate.version,
768 type=db_url_obj.get_backend_name(),
794 type=db_url_obj.get_backend_name(),
769 version=db_version,
795 version=db_version,
770 url=repr(db_url_obj)
796 url=repr(db_url_obj)
771 )
797 )
772 current_version = db_migrate.version
798 current_version = db_migrate.version
773 expected_version = rhodecode.__dbversion__
799 expected_version = rhodecode.__dbversion__
774 if state['type'] == STATE_OK and current_version != expected_version:
800 if state['type'] == STATE_OK and current_version != expected_version:
775 msg = 'Critical: database schema mismatch, ' \
801 msg = 'Critical: database schema mismatch, ' \
776 'expected version {}, got {}. ' \
802 'expected version {}, got {}. ' \
777 'Please run migrations on your database.'.format(
803 'Please run migrations on your database.'.format(
778 expected_version, current_version)
804 expected_version, current_version)
779 state = {'message': msg, 'type': STATE_ERR}
805 state = {'message': msg, 'type': STATE_ERR}
780
806
781 human_value = db_info.copy()
807 human_value = db_info.copy()
782 human_value['url'] = "{} @ migration version: {}".format(
808 human_value['url'] = "{} @ migration version: {}".format(
783 db_info['url'], db_info['migrate_version'])
809 db_info['url'], db_info['migrate_version'])
784 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
810 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
785 return SysInfoRes(value=db_info, state=state, human_value=human_value)
811 return SysInfoRes(value=db_info, state=state, human_value=human_value)
786
812
787
813
788 @register_sysinfo
814 @register_sysinfo
789 def server_info(environ):
815 def server_info(environ):
790 import rhodecode
816 import rhodecode
791 from rhodecode.lib.base import get_server_ip_addr, get_server_port
817 from rhodecode.lib.base import get_server_ip_addr, get_server_port
792
818
793 value = {
819 value = {
794 'server_ip': '{}:{}'.format(
820 'server_ip': '{}:{}'.format(
795 get_server_ip_addr(environ, log_errors=False),
821 get_server_ip_addr(environ, log_errors=False),
796 get_server_port(environ)
822 get_server_port(environ)
797 ),
823 ),
798 'server_id': rhodecode.CONFIG.get('instance_id'),
824 'server_id': rhodecode.CONFIG.get('instance_id'),
799 }
825 }
800 return SysInfoRes(value=value)
826 return SysInfoRes(value=value)
801
827
802
828
803 @register_sysinfo
829 @register_sysinfo
804 def usage_info():
830 def usage_info():
805 from rhodecode.model.db import User, Repository, true
831 from rhodecode.model.db import User, Repository, true
806 value = {
832 value = {
807 'users': User.query().count(),
833 'users': User.query().count(),
808 'users_active': User.query().filter(User.active == true()).count(),
834 'users_active': User.query().filter(User.active == true()).count(),
809 'repositories': Repository.query().count(),
835 'repositories': Repository.query().count(),
810 'repository_types': {
836 'repository_types': {
811 'hg': Repository.query().filter(
837 'hg': Repository.query().filter(
812 Repository.repo_type == 'hg').count(),
838 Repository.repo_type == 'hg').count(),
813 'git': Repository.query().filter(
839 'git': Repository.query().filter(
814 Repository.repo_type == 'git').count(),
840 Repository.repo_type == 'git').count(),
815 'svn': Repository.query().filter(
841 'svn': Repository.query().filter(
816 Repository.repo_type == 'svn').count(),
842 Repository.repo_type == 'svn').count(),
817 },
843 },
818 }
844 }
819 return SysInfoRes(value=value)
845 return SysInfoRes(value=value)
820
846
821
847
822 def get_system_info(environ):
848 def get_system_info(environ):
823 environ = environ or {}
849 environ = environ or {}
824 return {
850 return {
825 'rhodecode_app': SysInfo(rhodecode_app_info)(),
851 'rhodecode_app': SysInfo(rhodecode_app_info)(),
826 'rhodecode_config': SysInfo(rhodecode_config)(),
852 'rhodecode_config': SysInfo(rhodecode_config)(),
827 'rhodecode_usage': SysInfo(usage_info)(),
853 'rhodecode_usage': SysInfo(usage_info)(),
828 'python': SysInfo(python_info)(),
854 'python': SysInfo(python_info)(),
829 'py_modules': SysInfo(py_modules)(),
855 'py_modules': SysInfo(py_modules)(),
830
856
831 'platform': SysInfo(platform_type)(),
857 'platform': SysInfo(platform_type)(),
832 'locale': SysInfo(locale_info)(),
858 'locale': SysInfo(locale_info)(),
833 'server': SysInfo(server_info, environ=environ)(),
859 'server': SysInfo(server_info, environ=environ)(),
834 'database': SysInfo(database_info)(),
860 'database': SysInfo(database_info)(),
835 'ulimit': SysInfo(ulimit_info)(),
861 'ulimit': SysInfo(ulimit_info)(),
836 'storage': SysInfo(storage)(),
862 'storage': SysInfo(storage)(),
837 'storage_inodes': SysInfo(storage_inodes)(),
863 'storage_inodes': SysInfo(storage_inodes)(),
838 'storage_archive': SysInfo(storage_archives)(),
864 'storage_archive': SysInfo(storage_archives)(),
839 'storage_artifacts': SysInfo(storage_artifacts)(),
865 'storage_artifacts': SysInfo(storage_artifacts)(),
840 'storage_gist': SysInfo(storage_gist)(),
866 'storage_gist': SysInfo(storage_gist)(),
841 'storage_temp': SysInfo(storage_temp)(),
867 'storage_temp': SysInfo(storage_temp)(),
842
868
843 'search': SysInfo(search_info)(),
869 'search': SysInfo(search_info)(),
844
870
845 'uptime': SysInfo(uptime)(),
871 'uptime': SysInfo(uptime)(),
846 'load': SysInfo(machine_load)(),
872 'load': SysInfo(machine_load)(),
847 'cpu': SysInfo(cpu)(),
873 'cpu': SysInfo(cpu)(),
848 'memory': SysInfo(memory)(),
874 'memory': SysInfo(memory)(),
849
875
850 'vcs_backends': SysInfo(vcs_backends)(),
876 'vcs_backends': SysInfo(vcs_backends)(),
851 'vcs_server': SysInfo(vcs_server)(),
877 'vcs_server': SysInfo(vcs_server)(),
852
878
853 'vcs_server_config': SysInfo(vcs_server_config)(),
879 'vcs_server_config': SysInfo(vcs_server_config)(),
880 'rhodecode_server_config': SysInfo(rhodecode_server_config)(),
854
881
855 'git': SysInfo(git_info)(),
882 'git': SysInfo(git_info)(),
856 'hg': SysInfo(hg_info)(),
883 'hg': SysInfo(hg_info)(),
857 'svn': SysInfo(svn_info)(),
884 'svn': SysInfo(svn_info)(),
858 }
885 }
859
886
860
887
861 def load_system_info(key):
888 def load_system_info(key):
862 """
889 """
863 get_sys_info('vcs_server')
890 get_sys_info('vcs_server')
864 get_sys_info('database')
891 get_sys_info('database')
865 """
892 """
866 return SysInfo(registered_helpers[key])()
893 return SysInfo(registered_helpers[key])()
@@ -1,89 +1,103 b''
1
1
2 <div id="update_notice" style="display: none; margin: 0px 0px 30px 0px">
2 <div id="update_notice" style="display: none; margin: 0px 0px 30px 0px">
3 <div>${_('Checking for updates...')}</div>
3 <div>${_('Checking for updates...')}</div>
4 </div>
4 </div>
5
5
6
6
7 <div class="panel panel-default">
7 <div class="panel panel-default">
8 <div class="panel-heading">
8 <div class="panel-heading">
9 <h3 class="panel-title">${_('System Info')}</h3>
9 <h3 class="panel-title">${_('System Info')}</h3>
10 % if c.allowed_to_snapshot:
10 % if c.allowed_to_snapshot:
11 <a href="${h.route_path('admin_settings_system', _query={'snapshot':1})}" class="panel-edit">${_('create summary snapshot')}</a>
11 <a href="${h.route_path('admin_settings_system', _query={'snapshot':1})}" class="panel-edit">${_('create summary snapshot')}</a>
12 % endif
12 % endif
13 </div>
13 </div>
14 <div class="panel-body">
14 <div class="panel-body">
15 <dl class="dl-horizontal settings dt-400">
15 <dl class="dl-horizontal settings dt-400">
16 % for dt, dd, warn in c.data_items:
16 % for dt, dd, warn in c.data_items:
17 <dt>${dt}${':' if dt else '---'}</dt>
17 <dt>${dt}${':' if dt else '---'}</dt>
18 <dd>${dd}${'' if dt else '---'}
18 <dd>${dd}${'' if dt else '---'}
19 % if warn and warn['message']:
19 % if warn and warn['message']:
20 <div class="alert-${warn['type']}">
20 <div class="alert-${warn['type']}">
21 <strong>${warn['message']}</strong>
21 <strong>${warn['message']}</strong>
22 </div>
22 </div>
23 % endif
23 % endif
24 </dd>
24 </dd>
25 % endfor
25 % endfor
26 </dl>
26 </dl>
27 </div>
27 </div>
28 </div>
28 </div>
29
29
30 <div class="panel panel-default">
30 <div class="panel panel-default">
31 <div class="panel-heading">
31 <div class="panel-heading">
32 <h3 class="panel-title">${_('VCS Server')}</h3>
32 <h3 class="panel-title">${_('RhodeCode Server Config')}</h3>
33 </div>
34 <div class="panel-body">
35 <dl class="dl-horizontal settings dt-400">
36 % for dt, dd in c.rhodecode_data_items:
37 <dt>${dt}${':' if dt else '---'}</dt>
38 <dd>${dd}${'' if dt else '---'}</dd>
39 % endfor
40 </dl>
41 </div>
42 </div>
43
44 <div class="panel panel-default">
45 <div class="panel-heading">
46 <h3 class="panel-title">${_('VCS Server Config')}</h3>
33 </div>
47 </div>
34 <div class="panel-body">
48 <div class="panel-body">
35 <dl class="dl-horizontal settings dt-400">
49 <dl class="dl-horizontal settings dt-400">
36 % for dt, dd in c.vcsserver_data_items:
50 % for dt, dd in c.vcsserver_data_items:
37 <dt>${dt}${':' if dt else '---'}</dt>
51 <dt>${dt}${':' if dt else '---'}</dt>
38 <dd>${dd}${'' if dt else '---'}</dd>
52 <dd>${dd}${'' if dt else '---'}</dd>
39 % endfor
53 % endfor
40 </dl>
54 </dl>
41 </div>
55 </div>
42 </div>
56 </div>
43
57
44 <div class="panel panel-default">
58 <div class="panel panel-default">
45 <div class="panel-heading">
59 <div class="panel-heading">
46 <h3 class="panel-title">${_('Python Packages')}</h3>
60 <h3 class="panel-title">${_('Python Packages')}</h3>
47 </div>
61 </div>
48 <div class="panel-body">
62 <div class="panel-body">
49 <table>
63 <table>
50 <th></th>
64 <th></th>
51 <th></th>
65 <th></th>
52 <th></th>
66 <th></th>
53 % for name, package_data in c.py_modules['human_value']:
67 % for name, package_data in c.py_modules['human_value']:
54 <tr>
68 <tr>
55 <td>${name.lower()}</td>
69 <td>${name.lower()}</td>
56 <td>${package_data['version']}</td>
70 <td>${package_data['version']}</td>
57 <td>(${package_data['location']})</td>
71 <td>(${package_data['location']})</td>
58 </tr>
72 </tr>
59 % endfor
73 % endfor
60 </table>
74 </table>
61
75
62 </div>
76 </div>
63 </div>
77 </div>
64
78
65 <div class="panel panel-default">
79 <div class="panel panel-default">
66 <div class="panel-heading">
80 <div class="panel-heading">
67 <h3 class="panel-title">${_('Env Variables')}</h3>
81 <h3 class="panel-title">${_('Env Variables')}</h3>
68 </div>
82 </div>
69 <div class="panel-body">
83 <div class="panel-body">
70 <table>
84 <table>
71 <th></th>
85 <th></th>
72 <th></th>
86 <th></th>
73 % for env_key, env_val in c.env_data:
87 % for env_key, env_val in c.env_data:
74 <tr>
88 <tr>
75 <td style="vertical-align: top">${env_key}</td>
89 <td style="vertical-align: top">${env_key}</td>
76 <td>${env_val}</td>
90 <td>${env_val}</td>
77 </tr>
91 </tr>
78 % endfor
92 % endfor
79 </table>
93 </table>
80
94
81 </div>
95 </div>
82 </div>
96 </div>
83
97
84 <script>
98 <script>
85 $('#check_for_update').click(function(e){
99 $('#check_for_update').click(function(e){
86 $('#update_notice').show();
100 $('#update_notice').show();
87 $('#update_notice').load("${h.route_path('admin_settings_system_update', _query={'ver': request.GET.get('ver')})}");
101 $('#update_notice').load("${h.route_path('admin_settings_system_update', _query={'ver': request.GET.get('ver')})}");
88 })
102 })
89 </script>
103 </script>
General Comments 0
You need to be logged in to leave comments. Login now