##// END OF EJS Templates
feat(license): allow import of license from rhodecode_enterprise.license which got broken after python3 migration
super-admin -
r5530:6b2825dc default
parent child Browse files
Show More
@@ -0,0 +1,17 b''
1
2 def apply_license(*args, **kwargs):
3 pass
4
5 try:
6 from rc_license.models import apply_license
7 except ImportError:
8 pass
9
10
11 def apply_license_from_file(*args, **kwargs):
12 pass
13
14 try:
15 from rc_license.models import apply_license_from_file
16 except ImportError:
17 pass
@@ -1,124 +1,123 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
1 # Copyright (C) 2016-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 import logging
18 import logging
19
19
20 import click
20 import click
21 import pyramid.paster
21 import pyramid.paster
22
22
23 from rhodecode.lib.pyramid_utils import bootstrap
23 from rhodecode.lib.pyramid_utils import bootstrap
24 from rhodecode.lib.config_utils import get_app_config
24 from rhodecode.lib.config_utils import get_app_config
25 from rhodecode.lib.db_manage import DbManage
25 from rhodecode.lib.db_manage import DbManage
26 from rhodecode.lib.utils2 import get_encryption_key
26 from rhodecode.lib.utils2 import get_encryption_key
27 from rhodecode.model.db import Session
27 from rhodecode.model.db import Session
28
28
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32
32
33 @click.command()
33 @click.command()
34 @click.argument('ini_path', type=click.Path(exists=True))
34 @click.argument('ini_path', type=click.Path(exists=True))
35 @click.option(
35 @click.option(
36 '--force-yes/--force-no', default=None,
36 '--force-yes/--force-no', default=None,
37 help="Force yes/no to every question")
37 help="Force yes/no to every question")
38 @click.option(
38 @click.option(
39 '--user',
39 '--user',
40 default=None,
40 default=None,
41 help='Initial super-admin username')
41 help='Initial super-admin username')
42 @click.option(
42 @click.option(
43 '--email',
43 '--email',
44 default=None,
44 default=None,
45 help='Initial super-admin email address.')
45 help='Initial super-admin email address.')
46 @click.option(
46 @click.option(
47 '--password',
47 '--password',
48 default=None,
48 default=None,
49 help='Initial super-admin password. Minimum 6 chars.')
49 help='Initial super-admin password. Minimum 6 chars.')
50 @click.option(
50 @click.option(
51 '--api-key',
51 '--api-key',
52 help='Initial API key for the admin user')
52 help='Initial API key for the admin user')
53 @click.option(
53 @click.option(
54 '--repos',
54 '--repos',
55 default=None,
55 default=None,
56 help='Absolute path to storage location. This is storage for all '
56 help='Absolute path to storage location. This is storage for all '
57 'existing and future repositories, and repository groups.')
57 'existing and future repositories, and repository groups.')
58 @click.option(
58 @click.option(
59 '--public-access/--no-public-access',
59 '--public-access/--no-public-access',
60 default=None,
60 default=None,
61 help='Enable public access on this installation. '
61 help='Enable public access on this installation. '
62 'Default is public access enabled.')
62 'Default is public access enabled.')
63 @click.option(
63 @click.option(
64 '--skip-existing-db',
64 '--skip-existing-db',
65 default=False,
65 default=False,
66 is_flag=True,
66 is_flag=True,
67 help='Do not destroy and re-initialize the database if it already exist.')
67 help='Do not destroy and re-initialize the database if it already exist.')
68 @click.option(
68 @click.option(
69 '--apply-license-key',
69 '--apply-license-key',
70 default=False,
70 default=False,
71 is_flag=True,
71 is_flag=True,
72 help='Get the license key from a license file or ENV and apply during DB creation.')
72 help='Get the license key from a license file or ENV and apply during DB creation.')
73 def main(ini_path, force_yes, user, email, password, api_key, repos,
73 def main(ini_path, force_yes, user, email, password, api_key, repos,
74 public_access, skip_existing_db, apply_license_key):
74 public_access, skip_existing_db, apply_license_key):
75 return command(ini_path, force_yes, user, email, password, api_key,
75 return command(ini_path, force_yes, user, email, password, api_key,
76 repos, public_access, skip_existing_db, apply_license_key)
76 repos, public_access, skip_existing_db, apply_license_key)
77
77
78
78
79 def command(ini_path, force_yes, user, email, password, api_key, repos,
79 def command(ini_path, force_yes, user, email, password, api_key, repos,
80 public_access, skip_existing_db, apply_license_key):
80 public_access, skip_existing_db, apply_license_key):
81 # mapping of old parameters to new CLI from click
81 # mapping of old parameters to new CLI from click
82 options = dict(
82 options = dict(
83 username=user,
83 username=user,
84 email=email,
84 email=email,
85 password=password,
85 password=password,
86 api_key=api_key,
86 api_key=api_key,
87 repos_location=repos,
87 repos_location=repos,
88 force_ask=force_yes,
88 force_ask=force_yes,
89 public_access=public_access
89 public_access=public_access
90 )
90 )
91 pyramid.paster.setup_logging(ini_path)
91 pyramid.paster.setup_logging(ini_path)
92
92
93 config = get_app_config(ini_path)
93 config = get_app_config(ini_path)
94
94
95 db_uri = config['sqlalchemy.db1.url']
95 db_uri = config['sqlalchemy.db1.url']
96 enc_key = get_encryption_key(config)
96 enc_key = get_encryption_key(config)
97 dbmanage = DbManage(log_sql=True, dbconf=db_uri, root='.',
97 dbmanage = DbManage(log_sql=True, dbconf=db_uri, root='.',
98 tests=False, cli_args=options, enc_key=enc_key)
98 tests=False, cli_args=options, enc_key=enc_key)
99 if skip_existing_db and dbmanage.db_exists():
99 if skip_existing_db and dbmanage.db_exists():
100 return
100 return
101
101
102 dbmanage.create_tables(override=True)
102 dbmanage.create_tables(override=True)
103 dbmanage.set_db_version()
103 dbmanage.set_db_version()
104 opts = dbmanage.config_prompt(None)
104 opts = dbmanage.config_prompt(None)
105 dbmanage.create_settings(opts)
105 dbmanage.create_settings(opts)
106 dbmanage.create_default_user()
106 dbmanage.create_default_user()
107 dbmanage.create_admin_and_prompt()
107 dbmanage.create_admin_and_prompt()
108 dbmanage.create_permissions()
108 dbmanage.create_permissions()
109 dbmanage.populate_default_permissions()
109 dbmanage.populate_default_permissions()
110 if apply_license_key:
110 if apply_license_key:
111 try:
111 from rhodecode.model.license import apply_license_from_file
112 from rc_license.models import apply_trial_license_if_missing
112 license_file_path = config.get('license.import_path')
113 apply_trial_license_if_missing(force=True)
113 if license_file_path:
114 except ImportError:
114 apply_license_from_file(license_file_path, force=True)
115 pass
116
115
117 Session().commit()
116 Session().commit()
118
117
119 with bootstrap(ini_path, env={'RC_CMD_SETUP_RC': '1'}) as env:
118 with bootstrap(ini_path, env={'RC_CMD_SETUP_RC': '1'}) as env:
120 msg = 'Successfully initialized database, schema and default data.'
119 msg = 'Successfully initialized database, schema and default data.'
121 print()
120 print()
122 print('*' * len(msg))
121 print('*' * len(msg))
123 print(msg.upper())
122 print(msg.upper())
124 print('*' * len(msg))
123 print('*' * len(msg))
@@ -1,399 +1,414 b''
1 # Copyright (C) 2010-2023 RhodeCode GmbH
1 # Copyright (C) 2010-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 import io
18 import io
19 import shlex
19 import shlex
20
20
21 import math
21 import math
22 import re
22 import re
23 import os
23 import os
24 import datetime
24 import datetime
25 import logging
25 import logging
26 import queue
26 import queue
27 import subprocess
27 import subprocess
28
28
29
29
30 from dateutil.parser import parse
30 from dateutil.parser import parse
31 from pyramid.interfaces import IRoutesMapper
31 from pyramid.interfaces import IRoutesMapper
32 from pyramid.settings import asbool
32 from pyramid.settings import asbool
33 from pyramid.path import AssetResolver
33 from pyramid.path import AssetResolver
34 from threading import Thread
34 from threading import Thread
35
35
36 from rhodecode.config.jsroutes import generate_jsroutes_content
36 from rhodecode.config.jsroutes import generate_jsroutes_content
37 from rhodecode.lib.base import get_auth_user
37 from rhodecode.lib.base import get_auth_user
38 from rhodecode.lib.celerylib.loader import set_celery_conf
38 from rhodecode.lib.celerylib.loader import set_celery_conf
39
39
40 import rhodecode
40 import rhodecode
41
41
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 def add_renderer_globals(event):
46 def add_renderer_globals(event):
47 from rhodecode.lib import helpers
47 from rhodecode.lib import helpers
48
48
49 # TODO: When executed in pyramid view context the request is not available
49 # TODO: When executed in pyramid view context the request is not available
50 # in the event. Find a better solution to get the request.
50 # in the event. Find a better solution to get the request.
51 from pyramid.threadlocal import get_current_request
51 from pyramid.threadlocal import get_current_request
52 request = event['request'] or get_current_request()
52 request = event['request'] or get_current_request()
53
53
54 # Add Pyramid translation as '_' to context
54 # Add Pyramid translation as '_' to context
55 event['_'] = request.translate
55 event['_'] = request.translate
56 event['_ungettext'] = request.plularize
56 event['_ungettext'] = request.plularize
57 event['h'] = helpers
57 event['h'] = helpers
58
58
59
59
60 def set_user_lang(event):
60 def set_user_lang(event):
61 request = event.request
61 request = event.request
62 cur_user = getattr(request, 'user', None)
62 cur_user = getattr(request, 'user', None)
63
63
64 if cur_user:
64 if cur_user:
65 user_lang = cur_user.get_instance().user_data.get('language')
65 user_lang = cur_user.get_instance().user_data.get('language')
66 if user_lang:
66 if user_lang:
67 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
67 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
68 event.request._LOCALE_ = user_lang
68 event.request._LOCALE_ = user_lang
69
69
70
70
71 def update_celery_conf(event):
71 def update_celery_conf(event):
72 log.debug('Setting celery config from new request')
72 log.debug('Setting celery config from new request')
73 set_celery_conf(request=event.request, registry=event.request.registry)
73 set_celery_conf(request=event.request, registry=event.request.registry)
74
74
75
75
76 def add_request_user_context(event):
76 def add_request_user_context(event):
77 """
77 """
78 Adds auth user into request context
78 Adds auth user into request context
79 """
79 """
80
80
81 request = event.request
81 request = event.request
82 # access req_id as soon as possible
82 # access req_id as soon as possible
83 req_id = request.req_id
83 req_id = request.req_id
84
84
85 if hasattr(request, 'vcs_call'):
85 if hasattr(request, 'vcs_call'):
86 # skip vcs calls
86 # skip vcs calls
87 return
87 return
88
88
89 if hasattr(request, 'rpc_method'):
89 if hasattr(request, 'rpc_method'):
90 # skip api calls
90 # skip api calls
91 return
91 return
92
92
93 auth_user, auth_token = get_auth_user(request)
93 auth_user, auth_token = get_auth_user(request)
94 request.user = auth_user
94 request.user = auth_user
95 request.user_auth_token = auth_token
95 request.user_auth_token = auth_token
96 request.environ['rc_auth_user'] = auth_user
96 request.environ['rc_auth_user'] = auth_user
97 request.environ['rc_auth_user_id'] = str(auth_user.user_id)
97 request.environ['rc_auth_user_id'] = str(auth_user.user_id)
98 request.environ['rc_req_id'] = req_id
98 request.environ['rc_req_id'] = req_id
99
99
100
100
101 def reset_log_bucket(event):
101 def reset_log_bucket(event):
102 """
102 """
103 reset the log bucket on new request
103 reset the log bucket on new request
104 """
104 """
105 request = event.request
105 request = event.request
106 request.req_id_records_init()
106 request.req_id_records_init()
107
107
108
108
109 def scan_repositories_if_enabled(event):
109 def scan_repositories_if_enabled(event):
110 """
110 """
111 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
111 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
112 does a repository scan if enabled in the settings.
112 does a repository scan if enabled in the settings.
113 """
113 """
114 settings = event.app.registry.settings
114 settings = event.app.registry.settings
115 vcs_server_enabled = settings['vcs.server.enable']
115 vcs_server_enabled = settings['vcs.server.enable']
116 import_on_startup = settings['startup.import_repos']
116 import_on_startup = settings['startup.import_repos']
117 if vcs_server_enabled and import_on_startup:
117 if vcs_server_enabled and import_on_startup:
118 from rhodecode.model.scm import ScmModel
118 from rhodecode.model.scm import ScmModel
119 from rhodecode.lib.utils import repo2db_mapper
119 from rhodecode.lib.utils import repo2db_mapper
120 scm = ScmModel()
120 scm = ScmModel()
121 repositories = scm.repo_scan(scm.repos_path)
121 repositories = scm.repo_scan(scm.repos_path)
122 repo2db_mapper(repositories, remove_obsolete=False)
122 repo2db_mapper(repositories, remove_obsolete=False)
123
123
124
124
125 def write_metadata_if_needed(event):
125 def write_metadata_if_needed(event):
126 """
126 """
127 Writes upgrade metadata
127 Writes upgrade metadata
128 """
128 """
129 import rhodecode
129 import rhodecode
130 from rhodecode.lib import system_info
130 from rhodecode.lib import system_info
131 from rhodecode.lib import ext_json
131 from rhodecode.lib import ext_json
132
132
133 fname = '.rcmetadata.json'
133 fname = '.rcmetadata.json'
134 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
134 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
135 metadata_destination = os.path.join(ini_loc, fname)
135 metadata_destination = os.path.join(ini_loc, fname)
136
136
137 def get_update_age():
137 def get_update_age():
138 now = datetime.datetime.utcnow()
138 now = datetime.datetime.utcnow()
139
139
140 with open(metadata_destination, 'rb') as f:
140 with open(metadata_destination, 'rb') as f:
141 data = ext_json.json.loads(f.read())
141 data = ext_json.json.loads(f.read())
142 if 'created_on' in data:
142 if 'created_on' in data:
143 update_date = parse(data['created_on'])
143 update_date = parse(data['created_on'])
144 diff = now - update_date
144 diff = now - update_date
145 return diff.total_seconds() / 60.0
145 return diff.total_seconds() / 60.0
146
146
147 return 0
147 return 0
148
148
149 def write():
149 def write():
150 configuration = system_info.SysInfo(
150 configuration = system_info.SysInfo(
151 system_info.rhodecode_config)()['value']
151 system_info.rhodecode_config)()['value']
152 license_token = configuration['config']['license_token']
152 license_token = configuration['config']['license_token']
153
153
154 setup = dict(
154 setup = dict(
155 workers=configuration['config']['server:main'].get(
155 workers=configuration['config']['server:main'].get(
156 'workers', '?'),
156 'workers', '?'),
157 worker_type=configuration['config']['server:main'].get(
157 worker_type=configuration['config']['server:main'].get(
158 'worker_class', 'sync'),
158 'worker_class', 'sync'),
159 )
159 )
160 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
160 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
161 del dbinfo['url']
161 del dbinfo['url']
162
162
163 metadata = dict(
163 metadata = dict(
164 desc='upgrade metadata info',
164 desc='upgrade metadata info',
165 license_token=license_token,
165 license_token=license_token,
166 created_on=datetime.datetime.utcnow().isoformat(),
166 created_on=datetime.datetime.utcnow().isoformat(),
167 usage=system_info.SysInfo(system_info.usage_info)()['value'],
167 usage=system_info.SysInfo(system_info.usage_info)()['value'],
168 platform=system_info.SysInfo(system_info.platform_type)()['value'],
168 platform=system_info.SysInfo(system_info.platform_type)()['value'],
169 database=dbinfo,
169 database=dbinfo,
170 cpu=system_info.SysInfo(system_info.cpu)()['value'],
170 cpu=system_info.SysInfo(system_info.cpu)()['value'],
171 memory=system_info.SysInfo(system_info.memory)()['value'],
171 memory=system_info.SysInfo(system_info.memory)()['value'],
172 setup=setup
172 setup=setup
173 )
173 )
174
174
175 with open(metadata_destination, 'wb') as f:
175 with open(metadata_destination, 'wb') as f:
176 f.write(ext_json.json.dumps(metadata))
176 f.write(ext_json.json.dumps(metadata))
177
177
178 settings = event.app.registry.settings
178 settings = event.app.registry.settings
179 if settings.get('metadata.skip'):
179 if settings.get('metadata.skip'):
180 return
180 return
181
181
182 # only write this every 24h, workers restart caused unwanted delays
182 # only write this every 24h, workers restart caused unwanted delays
183 try:
183 try:
184 age_in_min = get_update_age()
184 age_in_min = get_update_age()
185 except Exception:
185 except Exception:
186 age_in_min = 0
186 age_in_min = 0
187
187
188 if age_in_min > 60 * 60 * 24:
188 if age_in_min > 60 * 60 * 24:
189 return
189 return
190
190
191 try:
191 try:
192 write()
192 write()
193 except Exception:
193 except Exception:
194 pass
194 pass
195
195
196
196
197 def write_usage_data(event):
197 def write_usage_data(event):
198 import rhodecode
198 import rhodecode
199 from rhodecode.lib import system_info
199 from rhodecode.lib import system_info
200 from rhodecode.lib import ext_json
200 from rhodecode.lib import ext_json
201
201
202 settings = event.app.registry.settings
202 settings = event.app.registry.settings
203 instance_tag = settings.get('metadata.write_usage_tag')
203 instance_tag = settings.get('metadata.write_usage_tag')
204 if not settings.get('metadata.write_usage'):
204 if not settings.get('metadata.write_usage'):
205 return
205 return
206
206
207 def get_update_age(dest_file):
207 def get_update_age(dest_file):
208 now = datetime.datetime.utcnow()
208 now = datetime.datetime.now(datetime.UTC)
209
209
210 with open(dest_file, 'rb') as f:
210 with open(dest_file, 'rb') as f:
211 data = ext_json.json.loads(f.read())
211 data = ext_json.json.loads(f.read())
212 if 'created_on' in data:
212 if 'created_on' in data:
213 update_date = parse(data['created_on'])
213 update_date = parse(data['created_on'])
214 diff = now - update_date
214 diff = now - update_date
215 return math.ceil(diff.total_seconds() / 60.0)
215 return math.ceil(diff.total_seconds() / 60.0)
216
216
217 return 0
217 return 0
218
218
219 utc_date = datetime.datetime.utcnow()
219 utc_date = datetime.datetime.now(datetime.UTC)
220 hour_quarter = int(math.ceil((utc_date.hour + utc_date.minute/60.0) / 6.))
220 hour_quarter = int(math.ceil((utc_date.hour + utc_date.minute/60.0) / 6.))
221 fname = '.rc_usage_{date.year}{date.month:02d}{date.day:02d}_{hour}.json'.format(
221 fname = f'.rc_usage_{utc_date.year}{utc_date.month:02d}{utc_date.day:02d}_{hour_quarter}.json'
222 date=utc_date, hour=hour_quarter)
223 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
222 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
224
223
225 usage_dir = os.path.join(ini_loc, '.rcusage')
224 usage_dir = os.path.join(ini_loc, '.rcusage')
226 if not os.path.isdir(usage_dir):
225 if not os.path.isdir(usage_dir):
227 os.makedirs(usage_dir)
226 os.makedirs(usage_dir)
228 usage_metadata_destination = os.path.join(usage_dir, fname)
227 usage_metadata_destination = os.path.join(usage_dir, fname)
229
228
230 try:
229 try:
231 age_in_min = get_update_age(usage_metadata_destination)
230 age_in_min = get_update_age(usage_metadata_destination)
232 except Exception:
231 except Exception:
233 age_in_min = 0
232 age_in_min = 0
234
233
235 # write every 6th hour
234 # write every 6th hour
236 if age_in_min and age_in_min < 60 * 6:
235 if age_in_min and age_in_min < 60 * 6:
237 log.debug('Usage file created %s minutes ago, skipping (threshold: %s minutes)...',
236 log.debug('Usage file created %s minutes ago, skipping (threshold: %s minutes)...',
238 age_in_min, 60 * 6)
237 age_in_min, 60 * 6)
239 return
238 return
240
239
241 def write(dest_file):
240 def write(dest_file):
242 configuration = system_info.SysInfo(system_info.rhodecode_config)()['value']
241 configuration = system_info.SysInfo(system_info.rhodecode_config)()['value']
243 license_token = configuration['config']['license_token']
242 license_token = configuration['config']['license_token']
244
243
245 metadata = dict(
244 metadata = dict(
246 desc='Usage data',
245 desc='Usage data',
247 instance_tag=instance_tag,
246 instance_tag=instance_tag,
248 license_token=license_token,
247 license_token=license_token,
249 created_on=datetime.datetime.utcnow().isoformat(),
248 created_on=datetime.datetime.utcnow().isoformat(),
250 usage=system_info.SysInfo(system_info.usage_info)()['value'],
249 usage=system_info.SysInfo(system_info.usage_info)()['value'],
251 )
250 )
252
251
253 with open(dest_file, 'wb') as f:
252 with open(dest_file, 'wb') as f:
254 f.write(ext_json.formatted_json(metadata))
253 f.write(ext_json.formatted_json(metadata))
255
254
256 try:
255 try:
257 log.debug('Writing usage file at: %s', usage_metadata_destination)
256 log.debug('Writing usage file at: %s', usage_metadata_destination)
258 write(usage_metadata_destination)
257 write(usage_metadata_destination)
259 except Exception:
258 except Exception:
260 pass
259 pass
261
260
262
261
263 def write_js_routes_if_enabled(event):
262 def write_js_routes_if_enabled(event):
264 registry = event.app.registry
263 registry = event.app.registry
265
264
266 mapper = registry.queryUtility(IRoutesMapper)
265 mapper = registry.queryUtility(IRoutesMapper)
267 _argument_prog = re.compile(r'\{(.*?)\}|:\((.*)\)')
266 _argument_prog = re.compile(r'\{(.*?)\}|:\((.*)\)')
268
267
269 def _extract_route_information(route):
268 def _extract_route_information(route):
270 """
269 """
271 Convert a route into tuple(name, path, args), eg:
270 Convert a route into tuple(name, path, args), eg:
272 ('show_user', '/profile/%(username)s', ['username'])
271 ('show_user', '/profile/%(username)s', ['username'])
273 """
272 """
274
273
275 route_path = route.pattern
274 route_path = route.pattern
276 pattern = route.pattern
275 pattern = route.pattern
277
276
278 def replace(matchobj):
277 def replace(matchobj):
279 if matchobj.group(1):
278 if matchobj.group(1):
280 return "%%(%s)s" % matchobj.group(1).split(':')[0]
279 return "%%(%s)s" % matchobj.group(1).split(':')[0]
281 else:
280 else:
282 return "%%(%s)s" % matchobj.group(2)
281 return "%%(%s)s" % matchobj.group(2)
283
282
284 route_path = _argument_prog.sub(replace, route_path)
283 route_path = _argument_prog.sub(replace, route_path)
285
284
286 if not route_path.startswith('/'):
285 if not route_path.startswith('/'):
287 route_path = f'/{route_path}'
286 route_path = f'/{route_path}'
288
287
289 return (
288 return (
290 route.name,
289 route.name,
291 route_path,
290 route_path,
292 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
291 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
293 for arg in _argument_prog.findall(pattern)]
292 for arg in _argument_prog.findall(pattern)]
294 )
293 )
295
294
296 def get_routes():
295 def get_routes():
297 # pyramid routes
296 # pyramid routes
298 for route in mapper.get_routes():
297 for route in mapper.get_routes():
299 if not route.name.startswith('__'):
298 if not route.name.startswith('__'):
300 yield _extract_route_information(route)
299 yield _extract_route_information(route)
301
300
302 if asbool(registry.settings.get('generate_js_files', 'false')):
301 if asbool(registry.settings.get('generate_js_files', 'false')):
303 static_path = AssetResolver().resolve('rhodecode:public').abspath()
302 static_path = AssetResolver().resolve('rhodecode:public').abspath()
304 jsroutes = get_routes()
303 jsroutes = get_routes()
305 jsroutes_file_content = generate_jsroutes_content(jsroutes)
304 jsroutes_file_content = generate_jsroutes_content(jsroutes)
306 jsroutes_file_path = os.path.join(
305 jsroutes_file_path = os.path.join(
307 static_path, 'js', 'rhodecode', 'routes.js')
306 static_path, 'js', 'rhodecode', 'routes.js')
308
307
309 try:
308 try:
310 with open(jsroutes_file_path, 'w', encoding='utf-8') as f:
309 with open(jsroutes_file_path, 'w', encoding='utf-8') as f:
311 f.write(jsroutes_file_content)
310 f.write(jsroutes_file_content)
312 log.debug('generated JS files in %s', jsroutes_file_path)
311 log.debug('generated JS files in %s', jsroutes_file_path)
313 except Exception:
312 except Exception:
314 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
313 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
315
314
316
315
316 def import_license_if_present(event):
317 """
318 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
319 does a import license key based on a presence of the file.
320 """
321 settings = event.app.registry.settings
322
323 license_file_path = settings.get('license.import_path')
324 force = settings.get('license.import_path_mode') == 'force'
325 if license_file_path:
326 from rhodecode.model.meta import Session
327 from rhodecode.model.license import apply_license_from_file
328 apply_license_from_file(license_file_path, force=force)
329 Session().commit()
330
331
317 class Subscriber(object):
332 class Subscriber(object):
318 """
333 """
319 Base class for subscribers to the pyramid event system.
334 Base class for subscribers to the pyramid event system.
320 """
335 """
321 def __call__(self, event):
336 def __call__(self, event):
322 self.run(event)
337 self.run(event)
323
338
324 def run(self, event):
339 def run(self, event):
325 raise NotImplementedError('Subclass has to implement this.')
340 raise NotImplementedError('Subclass has to implement this.')
326
341
327
342
328 class AsyncSubscriber(Subscriber):
343 class AsyncSubscriber(Subscriber):
329 """
344 """
330 Subscriber that handles the execution of events in a separate task to not
345 Subscriber that handles the execution of events in a separate task to not
331 block the execution of the code which triggers the event. It puts the
346 block the execution of the code which triggers the event. It puts the
332 received events into a queue from which the worker process takes them in
347 received events into a queue from which the worker process takes them in
333 order.
348 order.
334 """
349 """
335 def __init__(self):
350 def __init__(self):
336 self._stop = False
351 self._stop = False
337 self._eventq = queue.Queue()
352 self._eventq = queue.Queue()
338 self._worker = self.create_worker()
353 self._worker = self.create_worker()
339 self._worker.start()
354 self._worker.start()
340
355
341 def __call__(self, event):
356 def __call__(self, event):
342 self._eventq.put(event)
357 self._eventq.put(event)
343
358
344 def create_worker(self):
359 def create_worker(self):
345 worker = Thread(target=self.do_work)
360 worker = Thread(target=self.do_work)
346 worker.daemon = True
361 worker.daemon = True
347 return worker
362 return worker
348
363
349 def stop_worker(self):
364 def stop_worker(self):
350 self._stop = False
365 self._stop = False
351 self._eventq.put(None)
366 self._eventq.put(None)
352 self._worker.join()
367 self._worker.join()
353
368
354 def do_work(self):
369 def do_work(self):
355 while not self._stop:
370 while not self._stop:
356 event = self._eventq.get()
371 event = self._eventq.get()
357 if event is not None:
372 if event is not None:
358 self.run(event)
373 self.run(event)
359
374
360
375
361 class AsyncSubprocessSubscriber(AsyncSubscriber):
376 class AsyncSubprocessSubscriber(AsyncSubscriber):
362 """
377 """
363 Subscriber that uses the subprocess module to execute a command if an
378 Subscriber that uses the subprocess module to execute a command if an
364 event is received. Events are handled asynchronously::
379 event is received. Events are handled asynchronously::
365
380
366 subscriber = AsyncSubprocessSubscriber('ls -la', timeout=10)
381 subscriber = AsyncSubprocessSubscriber('ls -la', timeout=10)
367 subscriber(dummyEvent) # running __call__(event)
382 subscriber(dummyEvent) # running __call__(event)
368
383
369 """
384 """
370
385
371 def __init__(self, cmd, timeout=None):
386 def __init__(self, cmd, timeout=None):
372 if not isinstance(cmd, (list, tuple)):
387 if not isinstance(cmd, (list, tuple)):
373 cmd = shlex.split(cmd)
388 cmd = shlex.split(cmd)
374 super().__init__()
389 super().__init__()
375 self._cmd = cmd
390 self._cmd = cmd
376 self._timeout = timeout
391 self._timeout = timeout
377
392
378 def run(self, event):
393 def run(self, event):
379 cmd = self._cmd
394 cmd = self._cmd
380 timeout = self._timeout
395 timeout = self._timeout
381 log.debug('Executing command %s.', cmd)
396 log.debug('Executing command %s.', cmd)
382
397
383 try:
398 try:
384 output = subprocess.check_output(
399 output = subprocess.check_output(
385 cmd, timeout=timeout, stderr=subprocess.STDOUT)
400 cmd, timeout=timeout, stderr=subprocess.STDOUT)
386 log.debug('Command finished %s', cmd)
401 log.debug('Command finished %s', cmd)
387 if output:
402 if output:
388 log.debug('Command output: %s', output)
403 log.debug('Command output: %s', output)
389 except subprocess.TimeoutExpired as e:
404 except subprocess.TimeoutExpired as e:
390 log.exception('Timeout while executing command.')
405 log.exception('Timeout while executing command.')
391 if e.output:
406 if e.output:
392 log.error('Command output: %s', e.output)
407 log.error('Command output: %s', e.output)
393 except subprocess.CalledProcessError as e:
408 except subprocess.CalledProcessError as e:
394 log.exception('Error while executing command.')
409 log.exception('Error while executing command.')
395 if e.output:
410 if e.output:
396 log.error('Command output: %s', e.output)
411 log.error('Command output: %s', e.output)
397 except Exception:
412 except Exception:
398 log.exception(
413 log.exception(
399 'Exception while executing command %s.', cmd)
414 'Exception while executing command %s.', cmd)
General Comments 0
You need to be logged in to leave comments. Login now