##// END OF EJS Templates
feat(system-info): properly report storage stats after diskcache removal
super-admin -
r5421:0968de67 default
parent child Browse files
Show More
@@ -1,237 +1,238 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
168
169 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
169 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
170 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
170 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
171
171
172 (_('Archive cache storage type'), val('storage_archive')['type'], state('storage_archive')),
172 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
173 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
173 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
174 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
174
175
175 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
176 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
176 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
177 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
177
178
178 (_('Search info'), val('search')['text'], state('search')),
179 (_('Search info'), val('search')['text'], state('search')),
179 (_('Search location'), val('search')['location'], state('search')),
180 (_('Search location'), val('search')['location'], state('search')),
180 ('', '', ''), # spacer
181 ('', '', ''), # spacer
181
182
182 # VCS specific
183 # VCS specific
183 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
184 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
184 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
185 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
185 (_('GIT'), val('git'), state('git')),
186 (_('GIT'), val('git'), state('git')),
186 (_('HG'), val('hg'), state('hg')),
187 (_('HG'), val('hg'), state('hg')),
187 (_('SVN'), val('svn'), state('svn')),
188 (_('SVN'), val('svn'), state('svn')),
188
189
189 ]
190 ]
190
191
191 c.vcsserver_data_items = [
192 c.vcsserver_data_items = [
192 (k, v) for k,v in (val('vcs_server_config') or {}).items()
193 (k, v) for k,v in (val('vcs_server_config') or {}).items()
193 ]
194 ]
194
195
195 if snapshot:
196 if snapshot:
196 if c.allowed_to_snapshot:
197 if c.allowed_to_snapshot:
197 c.data_items.pop(0) # remove server info
198 c.data_items.pop(0) # remove server info
198 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
199 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
199 else:
200 else:
200 h.flash('You are not allowed to do this', category='warning')
201 h.flash('You are not allowed to do this', category='warning')
201 return self._get_template_context(c)
202 return self._get_template_context(c)
202
203
203 @LoginRequired()
204 @LoginRequired()
204 @HasPermissionAllDecorator('hg.admin')
205 @HasPermissionAllDecorator('hg.admin')
205 def settings_system_info_check_update(self):
206 def settings_system_info_check_update(self):
206 _ = self.request.translate
207 _ = self.request.translate
207 c = self.load_default_context()
208 c = self.load_default_context()
208
209
209 update_url = UpdateModel().get_update_url()
210 update_url = UpdateModel().get_update_url()
210
211
211 def _err(s):
212 def _err(s):
212 return '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
213 return '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
213 try:
214 try:
214 data = UpdateModel().get_update_data(update_url)
215 data = UpdateModel().get_update_data(update_url)
215 except urllib.error.URLError as e:
216 except urllib.error.URLError as e:
216 log.exception("Exception contacting upgrade server")
217 log.exception("Exception contacting upgrade server")
217 self.request.override_renderer = 'string'
218 self.request.override_renderer = 'string'
218 return _err('Failed to contact upgrade server: %r' % e)
219 return _err('Failed to contact upgrade server: %r' % e)
219 except ValueError as e:
220 except ValueError as e:
220 log.exception("Bad data sent from update server")
221 log.exception("Bad data sent from update server")
221 self.request.override_renderer = 'string'
222 self.request.override_renderer = 'string'
222 return _err('Bad data sent from update server')
223 return _err('Bad data sent from update server')
223
224
224 latest = data['versions'][0]
225 latest = data['versions'][0]
225
226
226 c.update_url = update_url
227 c.update_url = update_url
227 c.latest_data = latest
228 c.latest_data = latest
228 c.latest_ver = latest['version']
229 c.latest_ver = latest['version']
229 c.cur_ver = rhodecode.__version__
230 c.cur_ver = rhodecode.__version__
230 c.should_upgrade = False
231 c.should_upgrade = False
231
232
232 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
233 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
233 if is_oudated:
234 if is_oudated:
234 c.should_upgrade = True
235 c.should_upgrade = True
235 c.important_notices = latest['general']
236 c.important_notices = latest['general']
236 UpdateModel().store_version(latest['version'])
237 UpdateModel().store_version(latest['version'])
237 return self._get_template_context(c)
238 return self._get_template_context(c)
@@ -1,30 +1,71 b''
1 # Copyright (C) 2015-2024 RhodeCode GmbH
1 # Copyright (C) 2015-2024 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 import os
18
19
19
20
20 class ArchiveCacheLock(Exception):
21 class ArchiveCacheLock(Exception):
21 pass
22 pass
22
23
23
24
24 def archive_iterator(_reader, block_size: int = 4096 * 512):
25 def archive_iterator(_reader, block_size: int = 4096 * 512):
25 # 4096 * 64 = 64KB
26 # 4096 * 64 = 64KB
26 while 1:
27 while 1:
27 data = _reader.read(block_size)
28 data = _reader.read(block_size)
28 if not data:
29 if not data:
29 break
30 break
30 yield data
31 yield data
32
33
34 def get_directory_statistics(start_path):
35 """
36 total_files, total_size, directory_stats = get_directory_statistics(start_path)
37
38 print(f"Directory statistics for: {start_path}\n")
39 print(f"Total files: {total_files}")
40 print(f"Total size: {format_size(total_size)}\n")
41
42 :param start_path:
43 :return:
44 """
45
46 total_files = 0
47 total_size = 0
48 directory_stats = {}
49
50 for dir_path, dir_names, file_names in os.walk(start_path):
51 dir_size = 0
52 file_count = len(file_names)
53
54 for file in file_names:
55 filepath = os.path.join(dir_path, file)
56 file_size = os.path.getsize(filepath)
57 dir_size += file_size
58
59 directory_stats[dir_path] = {'file_count': file_count, 'size': dir_size}
60 total_files += file_count
61 total_size += dir_size
62
63 return total_files, total_size, directory_stats
64
65
66 def format_size(size):
67 # Convert size in bytes to a human-readable format (e.g., KB, MB, GB)
68 for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
69 if size < 1024:
70 return f"{size:.2f} {unit}"
71 size /= 1024
@@ -1,851 +1,834 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 '.rccontrol-profile/etc/ca-bundle.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'] = '{} cores at {} %'.format(value['cpu_count'], 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_archives():
399 def storage_archives():
400 import rhodecode
400 import rhodecode
401 from rhodecode.lib.utils import safe_str
402 from rhodecode.lib.helpers import format_byte_size_binary
401 from rhodecode.lib.helpers import format_byte_size_binary
402 from rhodecode.lib.rc_cache.archive_cache.utils import get_directory_statistics
403
403
404 storage_type = rhodecode.ConfigGet().get_str('archive_cache.backend.type')
404 storage_type = rhodecode.ConfigGet().get_str('archive_cache.backend.type')
405 storage_key = 'archive_cache.filesystem.store_dir'
405 storage_key = 'archive_cache.filesystem.store_dir'
406
406
407 default_msg = 'Archive cache storage is controlled by '\
407 default_msg = 'Archive cache storage is controlled by '\
408 f'{storage_key}=/path/to/cache option in the .ini file'
408 f'{storage_key}=/path/to/cache option in the .ini file'
409 path = rhodecode.ConfigGet().get_str(storage_key, missing=default_msg)
409 path = rhodecode.ConfigGet().get_str(storage_key, missing=default_msg)
410
410
411 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
411 value = dict(percent=0, used=0, total=0, items=0, path=path, text='', type=storage_type)
412 state = STATE_OK_DEFAULT
412 state = STATE_OK_DEFAULT
413 try:
413 try:
414 if storage_type != 'filesystem':
414 if storage_type != 'filesystem':
415 # raise Exc to stop reporting on different type
415 # raise Exc to stop reporting on different type
416 raise ValueError('Storage type must be "filesystem"')
416 raise ValueError('Storage type must be "filesystem"')
417
417
418 items_count = 0
418 total_files, total_size, _directory_stats = get_directory_statistics(path)
419 used = 0
420 for root, dirs, files in os.walk(path):
421 if root == path:
422 items_count = len(dirs)
423
419
424 for f in files:
425 try:
426 used += os.path.getsize(os.path.join(root, f))
427 except OSError:
428 pass
429 value.update({
420 value.update({
430 'percent': 100,
421 'percent': 100,
431 'used': used,
422 'used': total_size,
432 'total': used,
423 'total': total_size,
433 'items': items_count
424 'items': total_files
434 })
425 })
435
426
436 except Exception as e:
427 except Exception as e:
437 log.exception('failed to fetch archive cache storage')
428 log.exception('failed to fetch archive cache storage')
438 state = {'message': str(e), 'type': STATE_ERR}
429 state = {'message': str(e), 'type': STATE_ERR}
439
430
440 human_value = value.copy()
431 human_value = value.copy()
441 human_value['used'] = format_byte_size_binary(value['used'])
432 human_value['used'] = format_byte_size_binary(value['used'])
442 human_value['total'] = format_byte_size_binary(value['total'])
433 human_value['total'] = format_byte_size_binary(value['total'])
443 human_value['text'] = "{} ({} items)".format(
434 human_value['text'] = "{} ({} items)".format(
444 human_value['used'], value['items'])
435 human_value['used'], value['items'])
445
436
446 return SysInfoRes(value=value, state=state, human_value=human_value)
437 return SysInfoRes(value=value, state=state, human_value=human_value)
447
438
448
439
449 @register_sysinfo
440 @register_sysinfo
450 def storage_gist():
441 def storage_gist():
451 from rhodecode.model.gist import GIST_STORE_LOC
442 from rhodecode.model.gist import GIST_STORE_LOC
452 from rhodecode.lib.utils import safe_str, get_rhodecode_repo_store_path
443 from rhodecode.lib.utils import safe_str, get_rhodecode_repo_store_path
453 from rhodecode.lib.helpers import format_byte_size_binary
444 from rhodecode.lib.helpers import format_byte_size_binary
445 from rhodecode.lib.rc_cache.archive_cache.utils import get_directory_statistics
446
454 path = safe_str(os.path.join(
447 path = safe_str(os.path.join(
455 get_rhodecode_repo_store_path(), GIST_STORE_LOC))
448 get_rhodecode_repo_store_path(), GIST_STORE_LOC))
456
449
457 # gist storage
450 # gist storage
458 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
451 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
459 state = STATE_OK_DEFAULT
452 state = STATE_OK_DEFAULT
460
453
461 try:
454 try:
462 items_count = 0
455 total_files, total_size, _directory_stats = get_directory_statistics(path)
463 used = 0
464 for root, dirs, files in os.walk(path):
465 if root == path:
466 items_count = len(dirs)
467
468 for f in files:
469 try:
470 used += os.path.getsize(os.path.join(root, f))
471 except OSError:
472 pass
473 value.update({
456 value.update({
474 'percent': 100,
457 'percent': 100,
475 'used': used,
458 'used': total_size,
476 'total': used,
459 'total': total_size,
477 'items': items_count
460 'items': total_files
478 })
461 })
479 except Exception as e:
462 except Exception as e:
480 log.exception('failed to fetch gist storage items')
463 log.exception('failed to fetch gist storage items')
481 state = {'message': str(e), 'type': STATE_ERR}
464 state = {'message': str(e), 'type': STATE_ERR}
482
465
483 human_value = value.copy()
466 human_value = value.copy()
484 human_value['used'] = format_byte_size_binary(value['used'])
467 human_value['used'] = format_byte_size_binary(value['used'])
485 human_value['total'] = format_byte_size_binary(value['total'])
468 human_value['total'] = format_byte_size_binary(value['total'])
486 human_value['text'] = "{} ({} items)".format(
469 human_value['text'] = "{} ({} items)".format(
487 human_value['used'], value['items'])
470 human_value['used'], value['items'])
488
471
489 return SysInfoRes(value=value, state=state, human_value=human_value)
472 return SysInfoRes(value=value, state=state, human_value=human_value)
490
473
491
474
492 @register_sysinfo
475 @register_sysinfo
493 def storage_temp():
476 def storage_temp():
494 import tempfile
477 import tempfile
495 from rhodecode.lib.helpers import format_byte_size_binary
478 from rhodecode.lib.helpers import format_byte_size_binary
496
479
497 path = tempfile.gettempdir()
480 path = tempfile.gettempdir()
498 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
481 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
499 state = STATE_OK_DEFAULT
482 state = STATE_OK_DEFAULT
500
483
501 if not psutil:
484 if not psutil:
502 return SysInfoRes(value=value, state=state)
485 return SysInfoRes(value=value, state=state)
503
486
504 try:
487 try:
505 value.update(dict(psutil.disk_usage(path)._asdict()))
488 value.update(dict(psutil.disk_usage(path)._asdict()))
506 except Exception as e:
489 except Exception as e:
507 log.exception('Failed to fetch temp dir info')
490 log.exception('Failed to fetch temp dir info')
508 state = {'message': str(e), 'type': STATE_ERR}
491 state = {'message': str(e), 'type': STATE_ERR}
509
492
510 human_value = value.copy()
493 human_value = value.copy()
511 human_value['used'] = format_byte_size_binary(value['used'])
494 human_value['used'] = format_byte_size_binary(value['used'])
512 human_value['total'] = format_byte_size_binary(value['total'])
495 human_value['total'] = format_byte_size_binary(value['total'])
513 human_value['text'] = "{}/{}, {}% used".format(
496 human_value['text'] = "{}/{}, {}% used".format(
514 format_byte_size_binary(value['used']),
497 format_byte_size_binary(value['used']),
515 format_byte_size_binary(value['total']),
498 format_byte_size_binary(value['total']),
516 value['percent'])
499 value['percent'])
517
500
518 return SysInfoRes(value=value, state=state, human_value=human_value)
501 return SysInfoRes(value=value, state=state, human_value=human_value)
519
502
520
503
521 @register_sysinfo
504 @register_sysinfo
522 def search_info():
505 def search_info():
523 import rhodecode
506 import rhodecode
524 from rhodecode.lib.index import searcher_from_config
507 from rhodecode.lib.index import searcher_from_config
525
508
526 backend = rhodecode.CONFIG.get('search.module', '')
509 backend = rhodecode.CONFIG.get('search.module', '')
527 location = rhodecode.CONFIG.get('search.location', '')
510 location = rhodecode.CONFIG.get('search.location', '')
528
511
529 try:
512 try:
530 searcher = searcher_from_config(rhodecode.CONFIG)
513 searcher = searcher_from_config(rhodecode.CONFIG)
531 searcher = searcher.__class__.__name__
514 searcher = searcher.__class__.__name__
532 except Exception:
515 except Exception:
533 searcher = None
516 searcher = None
534
517
535 value = dict(
518 value = dict(
536 backend=backend, searcher=searcher, location=location, text='')
519 backend=backend, searcher=searcher, location=location, text='')
537 state = STATE_OK_DEFAULT
520 state = STATE_OK_DEFAULT
538
521
539 human_value = value.copy()
522 human_value = value.copy()
540 human_value['text'] = "backend:`{}`".format(human_value['backend'])
523 human_value['text'] = "backend:`{}`".format(human_value['backend'])
541
524
542 return SysInfoRes(value=value, state=state, human_value=human_value)
525 return SysInfoRes(value=value, state=state, human_value=human_value)
543
526
544
527
545 @register_sysinfo
528 @register_sysinfo
546 def git_info():
529 def git_info():
547 from rhodecode.lib.vcs.backends import git
530 from rhodecode.lib.vcs.backends import git
548 state = STATE_OK_DEFAULT
531 state = STATE_OK_DEFAULT
549 value = human_value = ''
532 value = human_value = ''
550 try:
533 try:
551 value = git.discover_git_version(raise_on_exc=True)
534 value = git.discover_git_version(raise_on_exc=True)
552 human_value = f'version reported from VCSServer: {value}'
535 human_value = f'version reported from VCSServer: {value}'
553 except Exception as e:
536 except Exception as e:
554 state = {'message': str(e), 'type': STATE_ERR}
537 state = {'message': str(e), 'type': STATE_ERR}
555
538
556 return SysInfoRes(value=value, state=state, human_value=human_value)
539 return SysInfoRes(value=value, state=state, human_value=human_value)
557
540
558
541
559 @register_sysinfo
542 @register_sysinfo
560 def hg_info():
543 def hg_info():
561 from rhodecode.lib.vcs.backends import hg
544 from rhodecode.lib.vcs.backends import hg
562 state = STATE_OK_DEFAULT
545 state = STATE_OK_DEFAULT
563 value = human_value = ''
546 value = human_value = ''
564 try:
547 try:
565 value = hg.discover_hg_version(raise_on_exc=True)
548 value = hg.discover_hg_version(raise_on_exc=True)
566 human_value = f'version reported from VCSServer: {value}'
549 human_value = f'version reported from VCSServer: {value}'
567 except Exception as e:
550 except Exception as e:
568 state = {'message': str(e), 'type': STATE_ERR}
551 state = {'message': str(e), 'type': STATE_ERR}
569 return SysInfoRes(value=value, state=state, human_value=human_value)
552 return SysInfoRes(value=value, state=state, human_value=human_value)
570
553
571
554
572 @register_sysinfo
555 @register_sysinfo
573 def svn_info():
556 def svn_info():
574 from rhodecode.lib.vcs.backends import svn
557 from rhodecode.lib.vcs.backends import svn
575 state = STATE_OK_DEFAULT
558 state = STATE_OK_DEFAULT
576 value = human_value = ''
559 value = human_value = ''
577 try:
560 try:
578 value = svn.discover_svn_version(raise_on_exc=True)
561 value = svn.discover_svn_version(raise_on_exc=True)
579 human_value = f'version reported from VCSServer: {value}'
562 human_value = f'version reported from VCSServer: {value}'
580 except Exception as e:
563 except Exception as e:
581 state = {'message': str(e), 'type': STATE_ERR}
564 state = {'message': str(e), 'type': STATE_ERR}
582 return SysInfoRes(value=value, state=state, human_value=human_value)
565 return SysInfoRes(value=value, state=state, human_value=human_value)
583
566
584
567
585 @register_sysinfo
568 @register_sysinfo
586 def vcs_backends():
569 def vcs_backends():
587 import rhodecode
570 import rhodecode
588 value = rhodecode.CONFIG.get('vcs.backends')
571 value = rhodecode.CONFIG.get('vcs.backends')
589 human_value = 'Enabled backends in order: {}'.format(','.join(value))
572 human_value = 'Enabled backends in order: {}'.format(','.join(value))
590 return SysInfoRes(value=value, human_value=human_value)
573 return SysInfoRes(value=value, human_value=human_value)
591
574
592
575
593 @register_sysinfo
576 @register_sysinfo
594 def vcs_server():
577 def vcs_server():
595 import rhodecode
578 import rhodecode
596 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
579 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
597
580
598 server_url = rhodecode.CONFIG.get('vcs.server')
581 server_url = rhodecode.CONFIG.get('vcs.server')
599 enabled = rhodecode.CONFIG.get('vcs.server.enable')
582 enabled = rhodecode.CONFIG.get('vcs.server.enable')
600 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
583 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
601 state = STATE_OK_DEFAULT
584 state = STATE_OK_DEFAULT
602 version = None
585 version = None
603 workers = 0
586 workers = 0
604
587
605 try:
588 try:
606 data = get_vcsserver_service_data()
589 data = get_vcsserver_service_data()
607 if data and 'version' in data:
590 if data and 'version' in data:
608 version = data['version']
591 version = data['version']
609
592
610 if data and 'config' in data:
593 if data and 'config' in data:
611 conf = data['config']
594 conf = data['config']
612 workers = conf.get('workers', 'NOT AVAILABLE')
595 workers = conf.get('workers', 'NOT AVAILABLE')
613
596
614 connection = 'connected'
597 connection = 'connected'
615 except Exception as e:
598 except Exception as e:
616 connection = 'failed'
599 connection = 'failed'
617 state = {'message': str(e), 'type': STATE_ERR}
600 state = {'message': str(e), 'type': STATE_ERR}
618
601
619 value = dict(
602 value = dict(
620 url=server_url,
603 url=server_url,
621 enabled=enabled,
604 enabled=enabled,
622 protocol=protocol,
605 protocol=protocol,
623 connection=connection,
606 connection=connection,
624 version=version,
607 version=version,
625 text='',
608 text='',
626 )
609 )
627
610
628 human_value = value.copy()
611 human_value = value.copy()
629 human_value['text'] = \
612 human_value['text'] = \
630 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
613 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
631 url=server_url, ver=version, workers=workers, mode=protocol,
614 url=server_url, ver=version, workers=workers, mode=protocol,
632 conn=connection)
615 conn=connection)
633
616
634 return SysInfoRes(value=value, state=state, human_value=human_value)
617 return SysInfoRes(value=value, state=state, human_value=human_value)
635
618
636
619
637 @register_sysinfo
620 @register_sysinfo
638 def vcs_server_config():
621 def vcs_server_config():
639 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
622 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
640 state = STATE_OK_DEFAULT
623 state = STATE_OK_DEFAULT
641
624
642 value = {}
625 value = {}
643 try:
626 try:
644 data = get_vcsserver_service_data()
627 data = get_vcsserver_service_data()
645 value = data['app_config']
628 value = data['app_config']
646 except Exception as e:
629 except Exception as e:
647 state = {'message': str(e), 'type': STATE_ERR}
630 state = {'message': str(e), 'type': STATE_ERR}
648
631
649 human_value = value.copy()
632 human_value = value.copy()
650 human_value['text'] = 'VCS Server config'
633 human_value['text'] = 'VCS Server config'
651
634
652 return SysInfoRes(value=value, state=state, human_value=human_value)
635 return SysInfoRes(value=value, state=state, human_value=human_value)
653
636
654
637
655 @register_sysinfo
638 @register_sysinfo
656 def rhodecode_app_info():
639 def rhodecode_app_info():
657 import rhodecode
640 import rhodecode
658 edition = rhodecode.CONFIG.get('rhodecode.edition')
641 edition = rhodecode.CONFIG.get('rhodecode.edition')
659
642
660 value = dict(
643 value = dict(
661 rhodecode_version=rhodecode.__version__,
644 rhodecode_version=rhodecode.__version__,
662 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
645 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
663 text=''
646 text=''
664 )
647 )
665 human_value = value.copy()
648 human_value = value.copy()
666 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
649 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
667 edition=edition, ver=value['rhodecode_version']
650 edition=edition, ver=value['rhodecode_version']
668 )
651 )
669 return SysInfoRes(value=value, human_value=human_value)
652 return SysInfoRes(value=value, human_value=human_value)
670
653
671
654
672 @register_sysinfo
655 @register_sysinfo
673 def rhodecode_config():
656 def rhodecode_config():
674 import rhodecode
657 import rhodecode
675 path = rhodecode.CONFIG.get('__file__')
658 path = rhodecode.CONFIG.get('__file__')
676 rhodecode_ini_safe = rhodecode.CONFIG.copy()
659 rhodecode_ini_safe = rhodecode.CONFIG.copy()
677 cert_path = get_cert_path(path)
660 cert_path = get_cert_path(path)
678
661
679 try:
662 try:
680 config = configparser.ConfigParser()
663 config = configparser.ConfigParser()
681 config.read(path)
664 config.read(path)
682 parsed_ini = config
665 parsed_ini = config
683 if parsed_ini.has_section('server:main'):
666 if parsed_ini.has_section('server:main'):
684 parsed_ini = dict(parsed_ini.items('server:main'))
667 parsed_ini = dict(parsed_ini.items('server:main'))
685 except Exception:
668 except Exception:
686 log.exception('Failed to read .ini file for display')
669 log.exception('Failed to read .ini file for display')
687 parsed_ini = {}
670 parsed_ini = {}
688
671
689 rhodecode_ini_safe['server:main'] = parsed_ini
672 rhodecode_ini_safe['server:main'] = parsed_ini
690
673
691 blacklist = [
674 blacklist = [
692 f'rhodecode_{LicenseModel.LICENSE_DB_KEY}',
675 f'rhodecode_{LicenseModel.LICENSE_DB_KEY}',
693 'routes.map',
676 'routes.map',
694 'sqlalchemy.db1.url',
677 'sqlalchemy.db1.url',
695 'channelstream.secret',
678 'channelstream.secret',
696 'beaker.session.secret',
679 'beaker.session.secret',
697 'rhodecode.encrypted_values.secret',
680 'rhodecode.encrypted_values.secret',
698 'rhodecode_auth_github_consumer_key',
681 'rhodecode_auth_github_consumer_key',
699 'rhodecode_auth_github_consumer_secret',
682 'rhodecode_auth_github_consumer_secret',
700 'rhodecode_auth_google_consumer_key',
683 'rhodecode_auth_google_consumer_key',
701 'rhodecode_auth_google_consumer_secret',
684 'rhodecode_auth_google_consumer_secret',
702 'rhodecode_auth_bitbucket_consumer_secret',
685 'rhodecode_auth_bitbucket_consumer_secret',
703 'rhodecode_auth_bitbucket_consumer_key',
686 'rhodecode_auth_bitbucket_consumer_key',
704 'rhodecode_auth_twitter_consumer_secret',
687 'rhodecode_auth_twitter_consumer_secret',
705 'rhodecode_auth_twitter_consumer_key',
688 'rhodecode_auth_twitter_consumer_key',
706
689
707 'rhodecode_auth_twitter_secret',
690 'rhodecode_auth_twitter_secret',
708 'rhodecode_auth_github_secret',
691 'rhodecode_auth_github_secret',
709 'rhodecode_auth_google_secret',
692 'rhodecode_auth_google_secret',
710 'rhodecode_auth_bitbucket_secret',
693 'rhodecode_auth_bitbucket_secret',
711
694
712 'appenlight.api_key',
695 'appenlight.api_key',
713 ('app_conf', 'sqlalchemy.db1.url')
696 ('app_conf', 'sqlalchemy.db1.url')
714 ]
697 ]
715 for k in blacklist:
698 for k in blacklist:
716 if isinstance(k, tuple):
699 if isinstance(k, tuple):
717 section, key = k
700 section, key = k
718 if section in rhodecode_ini_safe:
701 if section in rhodecode_ini_safe:
719 rhodecode_ini_safe[section] = '**OBFUSCATED**'
702 rhodecode_ini_safe[section] = '**OBFUSCATED**'
720 else:
703 else:
721 rhodecode_ini_safe.pop(k, None)
704 rhodecode_ini_safe.pop(k, None)
722
705
723 # TODO: maybe put some CONFIG checks here ?
706 # TODO: maybe put some CONFIG checks here ?
724 return SysInfoRes(value={'config': rhodecode_ini_safe,
707 return SysInfoRes(value={'config': rhodecode_ini_safe,
725 'path': path, 'cert_path': cert_path})
708 'path': path, 'cert_path': cert_path})
726
709
727
710
728 @register_sysinfo
711 @register_sysinfo
729 def database_info():
712 def database_info():
730 import rhodecode
713 import rhodecode
731 from sqlalchemy.engine import url as engine_url
714 from sqlalchemy.engine import url as engine_url
732 from rhodecode.model import meta
715 from rhodecode.model import meta
733 from rhodecode.model.meta import Session
716 from rhodecode.model.meta import Session
734 from rhodecode.model.db import DbMigrateVersion
717 from rhodecode.model.db import DbMigrateVersion
735
718
736 state = STATE_OK_DEFAULT
719 state = STATE_OK_DEFAULT
737
720
738 db_migrate = DbMigrateVersion.query().filter(
721 db_migrate = DbMigrateVersion.query().filter(
739 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
722 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
740
723
741 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
724 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
742
725
743 try:
726 try:
744 engine = meta.get_engine()
727 engine = meta.get_engine()
745 db_server_info = engine.dialect._get_server_version_info(
728 db_server_info = engine.dialect._get_server_version_info(
746 Session.connection(bind=engine))
729 Session.connection(bind=engine))
747 db_version = '.'.join(map(str, db_server_info))
730 db_version = '.'.join(map(str, db_server_info))
748 except Exception:
731 except Exception:
749 log.exception('failed to fetch db version')
732 log.exception('failed to fetch db version')
750 db_version = 'UNKNOWN'
733 db_version = 'UNKNOWN'
751
734
752 db_info = dict(
735 db_info = dict(
753 migrate_version=db_migrate.version,
736 migrate_version=db_migrate.version,
754 type=db_url_obj.get_backend_name(),
737 type=db_url_obj.get_backend_name(),
755 version=db_version,
738 version=db_version,
756 url=repr(db_url_obj)
739 url=repr(db_url_obj)
757 )
740 )
758 current_version = db_migrate.version
741 current_version = db_migrate.version
759 expected_version = rhodecode.__dbversion__
742 expected_version = rhodecode.__dbversion__
760 if state['type'] == STATE_OK and current_version != expected_version:
743 if state['type'] == STATE_OK and current_version != expected_version:
761 msg = 'Critical: database schema mismatch, ' \
744 msg = 'Critical: database schema mismatch, ' \
762 'expected version {}, got {}. ' \
745 'expected version {}, got {}. ' \
763 'Please run migrations on your database.'.format(
746 'Please run migrations on your database.'.format(
764 expected_version, current_version)
747 expected_version, current_version)
765 state = {'message': msg, 'type': STATE_ERR}
748 state = {'message': msg, 'type': STATE_ERR}
766
749
767 human_value = db_info.copy()
750 human_value = db_info.copy()
768 human_value['url'] = "{} @ migration version: {}".format(
751 human_value['url'] = "{} @ migration version: {}".format(
769 db_info['url'], db_info['migrate_version'])
752 db_info['url'], db_info['migrate_version'])
770 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
753 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
771 return SysInfoRes(value=db_info, state=state, human_value=human_value)
754 return SysInfoRes(value=db_info, state=state, human_value=human_value)
772
755
773
756
774 @register_sysinfo
757 @register_sysinfo
775 def server_info(environ):
758 def server_info(environ):
776 import rhodecode
759 import rhodecode
777 from rhodecode.lib.base import get_server_ip_addr, get_server_port
760 from rhodecode.lib.base import get_server_ip_addr, get_server_port
778
761
779 value = {
762 value = {
780 'server_ip': '{}:{}'.format(
763 'server_ip': '{}:{}'.format(
781 get_server_ip_addr(environ, log_errors=False),
764 get_server_ip_addr(environ, log_errors=False),
782 get_server_port(environ)
765 get_server_port(environ)
783 ),
766 ),
784 'server_id': rhodecode.CONFIG.get('instance_id'),
767 'server_id': rhodecode.CONFIG.get('instance_id'),
785 }
768 }
786 return SysInfoRes(value=value)
769 return SysInfoRes(value=value)
787
770
788
771
789 @register_sysinfo
772 @register_sysinfo
790 def usage_info():
773 def usage_info():
791 from rhodecode.model.db import User, Repository, true
774 from rhodecode.model.db import User, Repository, true
792 value = {
775 value = {
793 'users': User.query().count(),
776 'users': User.query().count(),
794 'users_active': User.query().filter(User.active == true()).count(),
777 'users_active': User.query().filter(User.active == true()).count(),
795 'repositories': Repository.query().count(),
778 'repositories': Repository.query().count(),
796 'repository_types': {
779 'repository_types': {
797 'hg': Repository.query().filter(
780 'hg': Repository.query().filter(
798 Repository.repo_type == 'hg').count(),
781 Repository.repo_type == 'hg').count(),
799 'git': Repository.query().filter(
782 'git': Repository.query().filter(
800 Repository.repo_type == 'git').count(),
783 Repository.repo_type == 'git').count(),
801 'svn': Repository.query().filter(
784 'svn': Repository.query().filter(
802 Repository.repo_type == 'svn').count(),
785 Repository.repo_type == 'svn').count(),
803 },
786 },
804 }
787 }
805 return SysInfoRes(value=value)
788 return SysInfoRes(value=value)
806
789
807
790
808 def get_system_info(environ):
791 def get_system_info(environ):
809 environ = environ or {}
792 environ = environ or {}
810 return {
793 return {
811 'rhodecode_app': SysInfo(rhodecode_app_info)(),
794 'rhodecode_app': SysInfo(rhodecode_app_info)(),
812 'rhodecode_config': SysInfo(rhodecode_config)(),
795 'rhodecode_config': SysInfo(rhodecode_config)(),
813 'rhodecode_usage': SysInfo(usage_info)(),
796 'rhodecode_usage': SysInfo(usage_info)(),
814 'python': SysInfo(python_info)(),
797 'python': SysInfo(python_info)(),
815 'py_modules': SysInfo(py_modules)(),
798 'py_modules': SysInfo(py_modules)(),
816
799
817 'platform': SysInfo(platform_type)(),
800 'platform': SysInfo(platform_type)(),
818 'locale': SysInfo(locale_info)(),
801 'locale': SysInfo(locale_info)(),
819 'server': SysInfo(server_info, environ=environ)(),
802 'server': SysInfo(server_info, environ=environ)(),
820 'database': SysInfo(database_info)(),
803 'database': SysInfo(database_info)(),
821 'ulimit': SysInfo(ulimit_info)(),
804 'ulimit': SysInfo(ulimit_info)(),
822 'storage': SysInfo(storage)(),
805 'storage': SysInfo(storage)(),
823 'storage_inodes': SysInfo(storage_inodes)(),
806 'storage_inodes': SysInfo(storage_inodes)(),
824 'storage_archive': SysInfo(storage_archives)(),
807 'storage_archive': SysInfo(storage_archives)(),
825 'storage_gist': SysInfo(storage_gist)(),
808 'storage_gist': SysInfo(storage_gist)(),
826 'storage_temp': SysInfo(storage_temp)(),
809 'storage_temp': SysInfo(storage_temp)(),
827
810
828 'search': SysInfo(search_info)(),
811 'search': SysInfo(search_info)(),
829
812
830 'uptime': SysInfo(uptime)(),
813 'uptime': SysInfo(uptime)(),
831 'load': SysInfo(machine_load)(),
814 'load': SysInfo(machine_load)(),
832 'cpu': SysInfo(cpu)(),
815 'cpu': SysInfo(cpu)(),
833 'memory': SysInfo(memory)(),
816 'memory': SysInfo(memory)(),
834
817
835 'vcs_backends': SysInfo(vcs_backends)(),
818 'vcs_backends': SysInfo(vcs_backends)(),
836 'vcs_server': SysInfo(vcs_server)(),
819 'vcs_server': SysInfo(vcs_server)(),
837
820
838 'vcs_server_config': SysInfo(vcs_server_config)(),
821 'vcs_server_config': SysInfo(vcs_server_config)(),
839
822
840 'git': SysInfo(git_info)(),
823 'git': SysInfo(git_info)(),
841 'hg': SysInfo(hg_info)(),
824 'hg': SysInfo(hg_info)(),
842 'svn': SysInfo(svn_info)(),
825 'svn': SysInfo(svn_info)(),
843 }
826 }
844
827
845
828
846 def load_system_info(key):
829 def load_system_info(key):
847 """
830 """
848 get_sys_info('vcs_server')
831 get_sys_info('vcs_server')
849 get_sys_info('database')
832 get_sys_info('database')
850 """
833 """
851 return SysInfo(registered_helpers[key])()
834 return SysInfo(registered_helpers[key])()
General Comments 0
You need to be logged in to leave comments. Login now