##// END OF EJS Templates
rc-upgrade-db: added option to force update a version.
marcink -
r3406:1afbe459 default
parent child Browse files
Show More
@@ -1,621 +1,624 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Database creation, and setup module for RhodeCode Enterprise. Used for creation
22 Database creation, and setup module for RhodeCode Enterprise. Used for creation
23 of database as well as for migration operations
23 of database as well as for migration operations
24 """
24 """
25
25
26 import os
26 import os
27 import sys
27 import sys
28 import time
28 import time
29 import uuid
29 import uuid
30 import logging
30 import logging
31 import getpass
31 import getpass
32 from os.path import dirname as dn, join as jn
32 from os.path import dirname as dn, join as jn
33
33
34 from sqlalchemy.engine import create_engine
34 from sqlalchemy.engine import create_engine
35
35
36 from rhodecode import __dbversion__
36 from rhodecode import __dbversion__
37 from rhodecode.model import init_model
37 from rhodecode.model import init_model
38 from rhodecode.model.user import UserModel
38 from rhodecode.model.user import UserModel
39 from rhodecode.model.db import (
39 from rhodecode.model.db import (
40 User, Permission, RhodeCodeUi, RhodeCodeSetting, UserToPerm,
40 User, Permission, RhodeCodeUi, RhodeCodeSetting, UserToPerm,
41 DbMigrateVersion, RepoGroup, UserRepoGroupToPerm, CacheKey, Repository)
41 DbMigrateVersion, RepoGroup, UserRepoGroupToPerm, CacheKey, Repository)
42 from rhodecode.model.meta import Session, Base
42 from rhodecode.model.meta import Session, Base
43 from rhodecode.model.permission import PermissionModel
43 from rhodecode.model.permission import PermissionModel
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.repo_group import RepoGroupModel
45 from rhodecode.model.repo_group import RepoGroupModel
46 from rhodecode.model.settings import SettingsModel
46 from rhodecode.model.settings import SettingsModel
47
47
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 def notify(msg):
52 def notify(msg):
53 """
53 """
54 Notification for migrations messages
54 Notification for migrations messages
55 """
55 """
56 ml = len(msg) + (4 * 2)
56 ml = len(msg) + (4 * 2)
57 print(('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)).upper())
57 print(('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)).upper())
58
58
59
59
60 class DbManage(object):
60 class DbManage(object):
61
61
62 def __init__(self, log_sql, dbconf, root, tests=False,
62 def __init__(self, log_sql, dbconf, root, tests=False,
63 SESSION=None, cli_args=None):
63 SESSION=None, cli_args=None):
64 self.dbname = dbconf.split('/')[-1]
64 self.dbname = dbconf.split('/')[-1]
65 self.tests = tests
65 self.tests = tests
66 self.root = root
66 self.root = root
67 self.dburi = dbconf
67 self.dburi = dbconf
68 self.log_sql = log_sql
68 self.log_sql = log_sql
69 self.db_exists = False
69 self.db_exists = False
70 self.cli_args = cli_args or {}
70 self.cli_args = cli_args or {}
71 self.init_db(SESSION=SESSION)
71 self.init_db(SESSION=SESSION)
72 self.ask_ok = self.get_ask_ok_func(self.cli_args.get('force_ask'))
72 self.ask_ok = self.get_ask_ok_func(self.cli_args.get('force_ask'))
73
73
74 def get_ask_ok_func(self, param):
74 def get_ask_ok_func(self, param):
75 if param not in [None]:
75 if param not in [None]:
76 # return a function lambda that has a default set to param
76 # return a function lambda that has a default set to param
77 return lambda *args, **kwargs: param
77 return lambda *args, **kwargs: param
78 else:
78 else:
79 from rhodecode.lib.utils import ask_ok
79 from rhodecode.lib.utils import ask_ok
80 return ask_ok
80 return ask_ok
81
81
82 def init_db(self, SESSION=None):
82 def init_db(self, SESSION=None):
83 if SESSION:
83 if SESSION:
84 self.sa = SESSION
84 self.sa = SESSION
85 else:
85 else:
86 # init new sessions
86 # init new sessions
87 engine = create_engine(self.dburi, echo=self.log_sql)
87 engine = create_engine(self.dburi, echo=self.log_sql)
88 init_model(engine)
88 init_model(engine)
89 self.sa = Session()
89 self.sa = Session()
90
90
91 def create_tables(self, override=False):
91 def create_tables(self, override=False):
92 """
92 """
93 Create a auth database
93 Create a auth database
94 """
94 """
95
95
96 log.info("Existing database with the same name is going to be destroyed.")
96 log.info("Existing database with the same name is going to be destroyed.")
97 log.info("Setup command will run DROP ALL command on that database.")
97 log.info("Setup command will run DROP ALL command on that database.")
98 if self.tests:
98 if self.tests:
99 destroy = True
99 destroy = True
100 else:
100 else:
101 destroy = self.ask_ok('Are you sure that you want to destroy the old database? [y/n]')
101 destroy = self.ask_ok('Are you sure that you want to destroy the old database? [y/n]')
102 if not destroy:
102 if not destroy:
103 log.info('Nothing done.')
103 log.info('Nothing done.')
104 sys.exit(0)
104 sys.exit(0)
105 if destroy:
105 if destroy:
106 Base.metadata.drop_all()
106 Base.metadata.drop_all()
107
107
108 checkfirst = not override
108 checkfirst = not override
109 Base.metadata.create_all(checkfirst=checkfirst)
109 Base.metadata.create_all(checkfirst=checkfirst)
110 log.info('Created tables for %s', self.dbname)
110 log.info('Created tables for %s', self.dbname)
111
111
112 def set_db_version(self):
112 def set_db_version(self):
113 ver = DbMigrateVersion()
113 ver = DbMigrateVersion()
114 ver.version = __dbversion__
114 ver.version = __dbversion__
115 ver.repository_id = 'rhodecode_db_migrations'
115 ver.repository_id = 'rhodecode_db_migrations'
116 ver.repository_path = 'versions'
116 ver.repository_path = 'versions'
117 self.sa.add(ver)
117 self.sa.add(ver)
118 log.info('db version set to: %s', __dbversion__)
118 log.info('db version set to: %s', __dbversion__)
119
119
120 def run_pre_migration_tasks(self):
120 def run_pre_migration_tasks(self):
121 """
121 """
122 Run various tasks before actually doing migrations
122 Run various tasks before actually doing migrations
123 """
123 """
124 # delete cache keys on each upgrade
124 # delete cache keys on each upgrade
125 total = CacheKey.query().count()
125 total = CacheKey.query().count()
126 log.info("Deleting (%s) cache keys now...", total)
126 log.info("Deleting (%s) cache keys now...", total)
127 CacheKey.delete_all_cache()
127 CacheKey.delete_all_cache()
128
128
129 def upgrade(self, version=None):
129 def upgrade(self, version=None):
130 """
130 """
131 Upgrades given database schema to given revision following
131 Upgrades given database schema to given revision following
132 all needed steps, to perform the upgrade
132 all needed steps, to perform the upgrade
133
133
134 """
134 """
135
135
136 from rhodecode.lib.dbmigrate.migrate.versioning import api
136 from rhodecode.lib.dbmigrate.migrate.versioning import api
137 from rhodecode.lib.dbmigrate.migrate.exceptions import \
137 from rhodecode.lib.dbmigrate.migrate.exceptions import \
138 DatabaseNotControlledError
138 DatabaseNotControlledError
139
139
140 if 'sqlite' in self.dburi:
140 if 'sqlite' in self.dburi:
141 print(
141 print(
142 '********************** WARNING **********************\n'
142 '********************** WARNING **********************\n'
143 'Make sure your version of sqlite is at least 3.7.X. \n'
143 'Make sure your version of sqlite is at least 3.7.X. \n'
144 'Earlier versions are known to fail on some migrations\n'
144 'Earlier versions are known to fail on some migrations\n'
145 '*****************************************************\n')
145 '*****************************************************\n')
146
146
147 upgrade = self.ask_ok(
147 upgrade = self.ask_ok(
148 'You are about to perform a database upgrade. Make '
148 'You are about to perform a database upgrade. Make '
149 'sure you have backed up your database. '
149 'sure you have backed up your database. '
150 'Continue ? [y/n]')
150 'Continue ? [y/n]')
151 if not upgrade:
151 if not upgrade:
152 log.info('No upgrade performed')
152 log.info('No upgrade performed')
153 sys.exit(0)
153 sys.exit(0)
154
154
155 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
155 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
156 'rhodecode/lib/dbmigrate')
156 'rhodecode/lib/dbmigrate')
157 db_uri = self.dburi
157 db_uri = self.dburi
158
158
159 if version:
160 DbMigrateVersion.set_version(version)
161
159 try:
162 try:
160 curr_version = version or api.db_version(db_uri, repository_path)
163 curr_version = api.db_version(db_uri, repository_path)
161 msg = ('Found current database db_uri under version '
164 msg = ('Found current database db_uri under version '
162 'control with version {}'.format(curr_version))
165 'control with version {}'.format(curr_version))
163
166
164 except (RuntimeError, DatabaseNotControlledError):
167 except (RuntimeError, DatabaseNotControlledError):
165 curr_version = 1
168 curr_version = 1
166 msg = ('Current database is not under version control. Setting '
169 msg = ('Current database is not under version control. Setting '
167 'as version %s' % curr_version)
170 'as version %s' % curr_version)
168 api.version_control(db_uri, repository_path, curr_version)
171 api.version_control(db_uri, repository_path, curr_version)
169
172
170 notify(msg)
173 notify(msg)
171
174
172 self.run_pre_migration_tasks()
175 self.run_pre_migration_tasks()
173
176
174 if curr_version == __dbversion__:
177 if curr_version == __dbversion__:
175 log.info('This database is already at the newest version')
178 log.info('This database is already at the newest version')
176 sys.exit(0)
179 sys.exit(0)
177
180
178 upgrade_steps = range(curr_version + 1, __dbversion__ + 1)
181 upgrade_steps = range(curr_version + 1, __dbversion__ + 1)
179 notify('attempting to upgrade database from '
182 notify('attempting to upgrade database from '
180 'version %s to version %s' % (curr_version, __dbversion__))
183 'version %s to version %s' % (curr_version, __dbversion__))
181
184
182 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
185 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
183 _step = None
186 _step = None
184 for step in upgrade_steps:
187 for step in upgrade_steps:
185 notify('performing upgrade step %s' % step)
188 notify('performing upgrade step %s' % step)
186 time.sleep(0.5)
189 time.sleep(0.5)
187
190
188 api.upgrade(db_uri, repository_path, step)
191 api.upgrade(db_uri, repository_path, step)
189 self.sa.rollback()
192 self.sa.rollback()
190 notify('schema upgrade for step %s completed' % (step,))
193 notify('schema upgrade for step %s completed' % (step,))
191
194
192 _step = step
195 _step = step
193
196
194 notify('upgrade to version %s successful' % _step)
197 notify('upgrade to version %s successful' % _step)
195
198
196 def fix_repo_paths(self):
199 def fix_repo_paths(self):
197 """
200 """
198 Fixes an old RhodeCode version path into new one without a '*'
201 Fixes an old RhodeCode version path into new one without a '*'
199 """
202 """
200
203
201 paths = self.sa.query(RhodeCodeUi)\
204 paths = self.sa.query(RhodeCodeUi)\
202 .filter(RhodeCodeUi.ui_key == '/')\
205 .filter(RhodeCodeUi.ui_key == '/')\
203 .scalar()
206 .scalar()
204
207
205 paths.ui_value = paths.ui_value.replace('*', '')
208 paths.ui_value = paths.ui_value.replace('*', '')
206
209
207 try:
210 try:
208 self.sa.add(paths)
211 self.sa.add(paths)
209 self.sa.commit()
212 self.sa.commit()
210 except Exception:
213 except Exception:
211 self.sa.rollback()
214 self.sa.rollback()
212 raise
215 raise
213
216
214 def fix_default_user(self):
217 def fix_default_user(self):
215 """
218 """
216 Fixes an old default user with some 'nicer' default values,
219 Fixes an old default user with some 'nicer' default values,
217 used mostly for anonymous access
220 used mostly for anonymous access
218 """
221 """
219 def_user = self.sa.query(User)\
222 def_user = self.sa.query(User)\
220 .filter(User.username == User.DEFAULT_USER)\
223 .filter(User.username == User.DEFAULT_USER)\
221 .one()
224 .one()
222
225
223 def_user.name = 'Anonymous'
226 def_user.name = 'Anonymous'
224 def_user.lastname = 'User'
227 def_user.lastname = 'User'
225 def_user.email = User.DEFAULT_USER_EMAIL
228 def_user.email = User.DEFAULT_USER_EMAIL
226
229
227 try:
230 try:
228 self.sa.add(def_user)
231 self.sa.add(def_user)
229 self.sa.commit()
232 self.sa.commit()
230 except Exception:
233 except Exception:
231 self.sa.rollback()
234 self.sa.rollback()
232 raise
235 raise
233
236
234 def fix_settings(self):
237 def fix_settings(self):
235 """
238 """
236 Fixes rhodecode settings and adds ga_code key for google analytics
239 Fixes rhodecode settings and adds ga_code key for google analytics
237 """
240 """
238
241
239 hgsettings3 = RhodeCodeSetting('ga_code', '')
242 hgsettings3 = RhodeCodeSetting('ga_code', '')
240
243
241 try:
244 try:
242 self.sa.add(hgsettings3)
245 self.sa.add(hgsettings3)
243 self.sa.commit()
246 self.sa.commit()
244 except Exception:
247 except Exception:
245 self.sa.rollback()
248 self.sa.rollback()
246 raise
249 raise
247
250
248 def create_admin_and_prompt(self):
251 def create_admin_and_prompt(self):
249
252
250 # defaults
253 # defaults
251 defaults = self.cli_args
254 defaults = self.cli_args
252 username = defaults.get('username')
255 username = defaults.get('username')
253 password = defaults.get('password')
256 password = defaults.get('password')
254 email = defaults.get('email')
257 email = defaults.get('email')
255
258
256 if username is None:
259 if username is None:
257 username = raw_input('Specify admin username:')
260 username = raw_input('Specify admin username:')
258 if password is None:
261 if password is None:
259 password = self._get_admin_password()
262 password = self._get_admin_password()
260 if not password:
263 if not password:
261 # second try
264 # second try
262 password = self._get_admin_password()
265 password = self._get_admin_password()
263 if not password:
266 if not password:
264 sys.exit()
267 sys.exit()
265 if email is None:
268 if email is None:
266 email = raw_input('Specify admin email:')
269 email = raw_input('Specify admin email:')
267 api_key = self.cli_args.get('api_key')
270 api_key = self.cli_args.get('api_key')
268 self.create_user(username, password, email, True,
271 self.create_user(username, password, email, True,
269 strict_creation_check=False,
272 strict_creation_check=False,
270 api_key=api_key)
273 api_key=api_key)
271
274
272 def _get_admin_password(self):
275 def _get_admin_password(self):
273 password = getpass.getpass('Specify admin password '
276 password = getpass.getpass('Specify admin password '
274 '(min 6 chars):')
277 '(min 6 chars):')
275 confirm = getpass.getpass('Confirm password:')
278 confirm = getpass.getpass('Confirm password:')
276
279
277 if password != confirm:
280 if password != confirm:
278 log.error('passwords mismatch')
281 log.error('passwords mismatch')
279 return False
282 return False
280 if len(password) < 6:
283 if len(password) < 6:
281 log.error('password is too short - use at least 6 characters')
284 log.error('password is too short - use at least 6 characters')
282 return False
285 return False
283
286
284 return password
287 return password
285
288
286 def create_test_admin_and_users(self):
289 def create_test_admin_and_users(self):
287 log.info('creating admin and regular test users')
290 log.info('creating admin and regular test users')
288 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
291 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
289 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
292 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
290 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
293 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
291 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
294 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
292 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
295 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
293
296
294 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
297 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
295 TEST_USER_ADMIN_EMAIL, True, api_key=True)
298 TEST_USER_ADMIN_EMAIL, True, api_key=True)
296
299
297 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
300 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
298 TEST_USER_REGULAR_EMAIL, False, api_key=True)
301 TEST_USER_REGULAR_EMAIL, False, api_key=True)
299
302
300 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
303 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
301 TEST_USER_REGULAR2_EMAIL, False, api_key=True)
304 TEST_USER_REGULAR2_EMAIL, False, api_key=True)
302
305
303 def create_ui_settings(self, repo_store_path):
306 def create_ui_settings(self, repo_store_path):
304 """
307 """
305 Creates ui settings, fills out hooks
308 Creates ui settings, fills out hooks
306 and disables dotencode
309 and disables dotencode
307 """
310 """
308 settings_model = SettingsModel(sa=self.sa)
311 settings_model = SettingsModel(sa=self.sa)
309 from rhodecode.lib.vcs.backends.hg import largefiles_store
312 from rhodecode.lib.vcs.backends.hg import largefiles_store
310 from rhodecode.lib.vcs.backends.git import lfs_store
313 from rhodecode.lib.vcs.backends.git import lfs_store
311
314
312 # Build HOOKS
315 # Build HOOKS
313 hooks = [
316 hooks = [
314 (RhodeCodeUi.HOOK_REPO_SIZE, 'python:vcsserver.hooks.repo_size'),
317 (RhodeCodeUi.HOOK_REPO_SIZE, 'python:vcsserver.hooks.repo_size'),
315
318
316 # HG
319 # HG
317 (RhodeCodeUi.HOOK_PRE_PULL, 'python:vcsserver.hooks.pre_pull'),
320 (RhodeCodeUi.HOOK_PRE_PULL, 'python:vcsserver.hooks.pre_pull'),
318 (RhodeCodeUi.HOOK_PULL, 'python:vcsserver.hooks.log_pull_action'),
321 (RhodeCodeUi.HOOK_PULL, 'python:vcsserver.hooks.log_pull_action'),
319 (RhodeCodeUi.HOOK_PRE_PUSH, 'python:vcsserver.hooks.pre_push'),
322 (RhodeCodeUi.HOOK_PRE_PUSH, 'python:vcsserver.hooks.pre_push'),
320 (RhodeCodeUi.HOOK_PRETX_PUSH, 'python:vcsserver.hooks.pre_push'),
323 (RhodeCodeUi.HOOK_PRETX_PUSH, 'python:vcsserver.hooks.pre_push'),
321 (RhodeCodeUi.HOOK_PUSH, 'python:vcsserver.hooks.log_push_action'),
324 (RhodeCodeUi.HOOK_PUSH, 'python:vcsserver.hooks.log_push_action'),
322 (RhodeCodeUi.HOOK_PUSH_KEY, 'python:vcsserver.hooks.key_push'),
325 (RhodeCodeUi.HOOK_PUSH_KEY, 'python:vcsserver.hooks.key_push'),
323
326
324 ]
327 ]
325
328
326 for key, value in hooks:
329 for key, value in hooks:
327 hook_obj = settings_model.get_ui_by_key(key)
330 hook_obj = settings_model.get_ui_by_key(key)
328 hooks2 = hook_obj if hook_obj else RhodeCodeUi()
331 hooks2 = hook_obj if hook_obj else RhodeCodeUi()
329 hooks2.ui_section = 'hooks'
332 hooks2.ui_section = 'hooks'
330 hooks2.ui_key = key
333 hooks2.ui_key = key
331 hooks2.ui_value = value
334 hooks2.ui_value = value
332 self.sa.add(hooks2)
335 self.sa.add(hooks2)
333
336
334 # enable largefiles
337 # enable largefiles
335 largefiles = RhodeCodeUi()
338 largefiles = RhodeCodeUi()
336 largefiles.ui_section = 'extensions'
339 largefiles.ui_section = 'extensions'
337 largefiles.ui_key = 'largefiles'
340 largefiles.ui_key = 'largefiles'
338 largefiles.ui_value = ''
341 largefiles.ui_value = ''
339 self.sa.add(largefiles)
342 self.sa.add(largefiles)
340
343
341 # set default largefiles cache dir, defaults to
344 # set default largefiles cache dir, defaults to
342 # /repo_store_location/.cache/largefiles
345 # /repo_store_location/.cache/largefiles
343 largefiles = RhodeCodeUi()
346 largefiles = RhodeCodeUi()
344 largefiles.ui_section = 'largefiles'
347 largefiles.ui_section = 'largefiles'
345 largefiles.ui_key = 'usercache'
348 largefiles.ui_key = 'usercache'
346 largefiles.ui_value = largefiles_store(repo_store_path)
349 largefiles.ui_value = largefiles_store(repo_store_path)
347
350
348 self.sa.add(largefiles)
351 self.sa.add(largefiles)
349
352
350 # set default lfs cache dir, defaults to
353 # set default lfs cache dir, defaults to
351 # /repo_store_location/.cache/lfs_store
354 # /repo_store_location/.cache/lfs_store
352 lfsstore = RhodeCodeUi()
355 lfsstore = RhodeCodeUi()
353 lfsstore.ui_section = 'vcs_git_lfs'
356 lfsstore.ui_section = 'vcs_git_lfs'
354 lfsstore.ui_key = 'store_location'
357 lfsstore.ui_key = 'store_location'
355 lfsstore.ui_value = lfs_store(repo_store_path)
358 lfsstore.ui_value = lfs_store(repo_store_path)
356
359
357 self.sa.add(lfsstore)
360 self.sa.add(lfsstore)
358
361
359 # enable hgsubversion disabled by default
362 # enable hgsubversion disabled by default
360 hgsubversion = RhodeCodeUi()
363 hgsubversion = RhodeCodeUi()
361 hgsubversion.ui_section = 'extensions'
364 hgsubversion.ui_section = 'extensions'
362 hgsubversion.ui_key = 'hgsubversion'
365 hgsubversion.ui_key = 'hgsubversion'
363 hgsubversion.ui_value = ''
366 hgsubversion.ui_value = ''
364 hgsubversion.ui_active = False
367 hgsubversion.ui_active = False
365 self.sa.add(hgsubversion)
368 self.sa.add(hgsubversion)
366
369
367 # enable hgevolve disabled by default
370 # enable hgevolve disabled by default
368 hgevolve = RhodeCodeUi()
371 hgevolve = RhodeCodeUi()
369 hgevolve.ui_section = 'extensions'
372 hgevolve.ui_section = 'extensions'
370 hgevolve.ui_key = 'evolve'
373 hgevolve.ui_key = 'evolve'
371 hgevolve.ui_value = ''
374 hgevolve.ui_value = ''
372 hgevolve.ui_active = False
375 hgevolve.ui_active = False
373 self.sa.add(hgevolve)
376 self.sa.add(hgevolve)
374
377
375 # enable hggit disabled by default
378 # enable hggit disabled by default
376 hggit = RhodeCodeUi()
379 hggit = RhodeCodeUi()
377 hggit.ui_section = 'extensions'
380 hggit.ui_section = 'extensions'
378 hggit.ui_key = 'hggit'
381 hggit.ui_key = 'hggit'
379 hggit.ui_value = ''
382 hggit.ui_value = ''
380 hggit.ui_active = False
383 hggit.ui_active = False
381 self.sa.add(hggit)
384 self.sa.add(hggit)
382
385
383 # set svn branch defaults
386 # set svn branch defaults
384 branches = ["/branches/*", "/trunk"]
387 branches = ["/branches/*", "/trunk"]
385 tags = ["/tags/*"]
388 tags = ["/tags/*"]
386
389
387 for branch in branches:
390 for branch in branches:
388 settings_model.create_ui_section_value(
391 settings_model.create_ui_section_value(
389 RhodeCodeUi.SVN_BRANCH_ID, branch)
392 RhodeCodeUi.SVN_BRANCH_ID, branch)
390
393
391 for tag in tags:
394 for tag in tags:
392 settings_model.create_ui_section_value(RhodeCodeUi.SVN_TAG_ID, tag)
395 settings_model.create_ui_section_value(RhodeCodeUi.SVN_TAG_ID, tag)
393
396
394 def create_auth_plugin_options(self, skip_existing=False):
397 def create_auth_plugin_options(self, skip_existing=False):
395 """
398 """
396 Create default auth plugin settings, and make it active
399 Create default auth plugin settings, and make it active
397
400
398 :param skip_existing:
401 :param skip_existing:
399 """
402 """
400
403
401 for k, v, t in [('auth_plugins', 'egg:rhodecode-enterprise-ce#rhodecode', 'list'),
404 for k, v, t in [('auth_plugins', 'egg:rhodecode-enterprise-ce#rhodecode', 'list'),
402 ('auth_rhodecode_enabled', 'True', 'bool')]:
405 ('auth_rhodecode_enabled', 'True', 'bool')]:
403 if (skip_existing and
406 if (skip_existing and
404 SettingsModel().get_setting_by_name(k) is not None):
407 SettingsModel().get_setting_by_name(k) is not None):
405 log.debug('Skipping option %s', k)
408 log.debug('Skipping option %s', k)
406 continue
409 continue
407 setting = RhodeCodeSetting(k, v, t)
410 setting = RhodeCodeSetting(k, v, t)
408 self.sa.add(setting)
411 self.sa.add(setting)
409
412
410 def create_default_options(self, skip_existing=False):
413 def create_default_options(self, skip_existing=False):
411 """Creates default settings"""
414 """Creates default settings"""
412
415
413 for k, v, t in [
416 for k, v, t in [
414 ('default_repo_enable_locking', False, 'bool'),
417 ('default_repo_enable_locking', False, 'bool'),
415 ('default_repo_enable_downloads', False, 'bool'),
418 ('default_repo_enable_downloads', False, 'bool'),
416 ('default_repo_enable_statistics', False, 'bool'),
419 ('default_repo_enable_statistics', False, 'bool'),
417 ('default_repo_private', False, 'bool'),
420 ('default_repo_private', False, 'bool'),
418 ('default_repo_type', 'hg', 'unicode')]:
421 ('default_repo_type', 'hg', 'unicode')]:
419
422
420 if (skip_existing and
423 if (skip_existing and
421 SettingsModel().get_setting_by_name(k) is not None):
424 SettingsModel().get_setting_by_name(k) is not None):
422 log.debug('Skipping option %s', k)
425 log.debug('Skipping option %s', k)
423 continue
426 continue
424 setting = RhodeCodeSetting(k, v, t)
427 setting = RhodeCodeSetting(k, v, t)
425 self.sa.add(setting)
428 self.sa.add(setting)
426
429
427 def fixup_groups(self):
430 def fixup_groups(self):
428 def_usr = User.get_default_user()
431 def_usr = User.get_default_user()
429 for g in RepoGroup.query().all():
432 for g in RepoGroup.query().all():
430 g.group_name = g.get_new_name(g.name)
433 g.group_name = g.get_new_name(g.name)
431 self.sa.add(g)
434 self.sa.add(g)
432 # get default perm
435 # get default perm
433 default = UserRepoGroupToPerm.query()\
436 default = UserRepoGroupToPerm.query()\
434 .filter(UserRepoGroupToPerm.group == g)\
437 .filter(UserRepoGroupToPerm.group == g)\
435 .filter(UserRepoGroupToPerm.user == def_usr)\
438 .filter(UserRepoGroupToPerm.user == def_usr)\
436 .scalar()
439 .scalar()
437
440
438 if default is None:
441 if default is None:
439 log.debug('missing default permission for group %s adding', g)
442 log.debug('missing default permission for group %s adding', g)
440 perm_obj = RepoGroupModel()._create_default_perms(g)
443 perm_obj = RepoGroupModel()._create_default_perms(g)
441 self.sa.add(perm_obj)
444 self.sa.add(perm_obj)
442
445
443 def reset_permissions(self, username):
446 def reset_permissions(self, username):
444 """
447 """
445 Resets permissions to default state, useful when old systems had
448 Resets permissions to default state, useful when old systems had
446 bad permissions, we must clean them up
449 bad permissions, we must clean them up
447
450
448 :param username:
451 :param username:
449 """
452 """
450 default_user = User.get_by_username(username)
453 default_user = User.get_by_username(username)
451 if not default_user:
454 if not default_user:
452 return
455 return
453
456
454 u2p = UserToPerm.query()\
457 u2p = UserToPerm.query()\
455 .filter(UserToPerm.user == default_user).all()
458 .filter(UserToPerm.user == default_user).all()
456 fixed = False
459 fixed = False
457 if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
460 if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
458 for p in u2p:
461 for p in u2p:
459 Session().delete(p)
462 Session().delete(p)
460 fixed = True
463 fixed = True
461 self.populate_default_permissions()
464 self.populate_default_permissions()
462 return fixed
465 return fixed
463
466
464 def update_repo_info(self):
467 def update_repo_info(self):
465 RepoModel.update_repoinfo()
468 RepoModel.update_repoinfo()
466
469
467 def config_prompt(self, test_repo_path='', retries=3):
470 def config_prompt(self, test_repo_path='', retries=3):
468 defaults = self.cli_args
471 defaults = self.cli_args
469 _path = defaults.get('repos_location')
472 _path = defaults.get('repos_location')
470 if retries == 3:
473 if retries == 3:
471 log.info('Setting up repositories config')
474 log.info('Setting up repositories config')
472
475
473 if _path is not None:
476 if _path is not None:
474 path = _path
477 path = _path
475 elif not self.tests and not test_repo_path:
478 elif not self.tests and not test_repo_path:
476 path = raw_input(
479 path = raw_input(
477 'Enter a valid absolute path to store repositories. '
480 'Enter a valid absolute path to store repositories. '
478 'All repositories in that path will be added automatically:'
481 'All repositories in that path will be added automatically:'
479 )
482 )
480 else:
483 else:
481 path = test_repo_path
484 path = test_repo_path
482 path_ok = True
485 path_ok = True
483
486
484 # check proper dir
487 # check proper dir
485 if not os.path.isdir(path):
488 if not os.path.isdir(path):
486 path_ok = False
489 path_ok = False
487 log.error('Given path %s is not a valid directory', path)
490 log.error('Given path %s is not a valid directory', path)
488
491
489 elif not os.path.isabs(path):
492 elif not os.path.isabs(path):
490 path_ok = False
493 path_ok = False
491 log.error('Given path %s is not an absolute path', path)
494 log.error('Given path %s is not an absolute path', path)
492
495
493 # check if path is at least readable.
496 # check if path is at least readable.
494 if not os.access(path, os.R_OK):
497 if not os.access(path, os.R_OK):
495 path_ok = False
498 path_ok = False
496 log.error('Given path %s is not readable', path)
499 log.error('Given path %s is not readable', path)
497
500
498 # check write access, warn user about non writeable paths
501 # check write access, warn user about non writeable paths
499 elif not os.access(path, os.W_OK) and path_ok:
502 elif not os.access(path, os.W_OK) and path_ok:
500 log.warning('No write permission to given path %s', path)
503 log.warning('No write permission to given path %s', path)
501
504
502 q = ('Given path %s is not writeable, do you want to '
505 q = ('Given path %s is not writeable, do you want to '
503 'continue with read only mode ? [y/n]' % (path,))
506 'continue with read only mode ? [y/n]' % (path,))
504 if not self.ask_ok(q):
507 if not self.ask_ok(q):
505 log.error('Canceled by user')
508 log.error('Canceled by user')
506 sys.exit(-1)
509 sys.exit(-1)
507
510
508 if retries == 0:
511 if retries == 0:
509 sys.exit('max retries reached')
512 sys.exit('max retries reached')
510 if not path_ok:
513 if not path_ok:
511 retries -= 1
514 retries -= 1
512 return self.config_prompt(test_repo_path, retries)
515 return self.config_prompt(test_repo_path, retries)
513
516
514 real_path = os.path.normpath(os.path.realpath(path))
517 real_path = os.path.normpath(os.path.realpath(path))
515
518
516 if real_path != os.path.normpath(path):
519 if real_path != os.path.normpath(path):
517 q = ('Path looks like a symlink, RhodeCode Enterprise will store '
520 q = ('Path looks like a symlink, RhodeCode Enterprise will store '
518 'given path as %s ? [y/n]') % (real_path,)
521 'given path as %s ? [y/n]') % (real_path,)
519 if not self.ask_ok(q):
522 if not self.ask_ok(q):
520 log.error('Canceled by user')
523 log.error('Canceled by user')
521 sys.exit(-1)
524 sys.exit(-1)
522
525
523 return real_path
526 return real_path
524
527
525 def create_settings(self, path):
528 def create_settings(self, path):
526
529
527 self.create_ui_settings(path)
530 self.create_ui_settings(path)
528
531
529 ui_config = [
532 ui_config = [
530 ('web', 'push_ssl', 'False'),
533 ('web', 'push_ssl', 'False'),
531 ('web', 'allow_archive', 'gz zip bz2'),
534 ('web', 'allow_archive', 'gz zip bz2'),
532 ('web', 'allow_push', '*'),
535 ('web', 'allow_push', '*'),
533 ('web', 'baseurl', '/'),
536 ('web', 'baseurl', '/'),
534 ('paths', '/', path),
537 ('paths', '/', path),
535 ('phases', 'publish', 'True')
538 ('phases', 'publish', 'True')
536 ]
539 ]
537 for section, key, value in ui_config:
540 for section, key, value in ui_config:
538 ui_conf = RhodeCodeUi()
541 ui_conf = RhodeCodeUi()
539 setattr(ui_conf, 'ui_section', section)
542 setattr(ui_conf, 'ui_section', section)
540 setattr(ui_conf, 'ui_key', key)
543 setattr(ui_conf, 'ui_key', key)
541 setattr(ui_conf, 'ui_value', value)
544 setattr(ui_conf, 'ui_value', value)
542 self.sa.add(ui_conf)
545 self.sa.add(ui_conf)
543
546
544 # rhodecode app settings
547 # rhodecode app settings
545 settings = [
548 settings = [
546 ('realm', 'RhodeCode', 'unicode'),
549 ('realm', 'RhodeCode', 'unicode'),
547 ('title', '', 'unicode'),
550 ('title', '', 'unicode'),
548 ('pre_code', '', 'unicode'),
551 ('pre_code', '', 'unicode'),
549 ('post_code', '', 'unicode'),
552 ('post_code', '', 'unicode'),
550 ('show_public_icon', True, 'bool'),
553 ('show_public_icon', True, 'bool'),
551 ('show_private_icon', True, 'bool'),
554 ('show_private_icon', True, 'bool'),
552 ('stylify_metatags', False, 'bool'),
555 ('stylify_metatags', False, 'bool'),
553 ('dashboard_items', 100, 'int'),
556 ('dashboard_items', 100, 'int'),
554 ('admin_grid_items', 25, 'int'),
557 ('admin_grid_items', 25, 'int'),
555 ('show_version', True, 'bool'),
558 ('show_version', True, 'bool'),
556 ('use_gravatar', False, 'bool'),
559 ('use_gravatar', False, 'bool'),
557 ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
560 ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
558 ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
561 ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
559 ('support_url', '', 'unicode'),
562 ('support_url', '', 'unicode'),
560 ('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'),
563 ('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'),
561 ('show_revision_number', True, 'bool'),
564 ('show_revision_number', True, 'bool'),
562 ('show_sha_length', 12, 'int'),
565 ('show_sha_length', 12, 'int'),
563 ]
566 ]
564
567
565 for key, val, type_ in settings:
568 for key, val, type_ in settings:
566 sett = RhodeCodeSetting(key, val, type_)
569 sett = RhodeCodeSetting(key, val, type_)
567 self.sa.add(sett)
570 self.sa.add(sett)
568
571
569 self.create_auth_plugin_options()
572 self.create_auth_plugin_options()
570 self.create_default_options()
573 self.create_default_options()
571
574
572 log.info('created ui config')
575 log.info('created ui config')
573
576
574 def create_user(self, username, password, email='', admin=False,
577 def create_user(self, username, password, email='', admin=False,
575 strict_creation_check=True, api_key=None):
578 strict_creation_check=True, api_key=None):
576 log.info('creating user `%s`', username)
579 log.info('creating user `%s`', username)
577 user = UserModel().create_or_update(
580 user = UserModel().create_or_update(
578 username, password, email, firstname=u'RhodeCode', lastname=u'Admin',
581 username, password, email, firstname=u'RhodeCode', lastname=u'Admin',
579 active=True, admin=admin, extern_type="rhodecode",
582 active=True, admin=admin, extern_type="rhodecode",
580 strict_creation_check=strict_creation_check)
583 strict_creation_check=strict_creation_check)
581
584
582 if api_key:
585 if api_key:
583 log.info('setting a new default auth token for user `%s`', username)
586 log.info('setting a new default auth token for user `%s`', username)
584 UserModel().add_auth_token(
587 UserModel().add_auth_token(
585 user=user, lifetime_minutes=-1,
588 user=user, lifetime_minutes=-1,
586 role=UserModel.auth_token_role.ROLE_ALL,
589 role=UserModel.auth_token_role.ROLE_ALL,
587 description=u'BUILTIN TOKEN')
590 description=u'BUILTIN TOKEN')
588
591
589 def create_default_user(self):
592 def create_default_user(self):
590 log.info('creating default user')
593 log.info('creating default user')
591 # create default user for handling default permissions.
594 # create default user for handling default permissions.
592 user = UserModel().create_or_update(username=User.DEFAULT_USER,
595 user = UserModel().create_or_update(username=User.DEFAULT_USER,
593 password=str(uuid.uuid1())[:20],
596 password=str(uuid.uuid1())[:20],
594 email=User.DEFAULT_USER_EMAIL,
597 email=User.DEFAULT_USER_EMAIL,
595 firstname=u'Anonymous',
598 firstname=u'Anonymous',
596 lastname=u'User',
599 lastname=u'User',
597 strict_creation_check=False)
600 strict_creation_check=False)
598 # based on configuration options activate/de-activate this user which
601 # based on configuration options activate/de-activate this user which
599 # controlls anonymous access
602 # controlls anonymous access
600 if self.cli_args.get('public_access') is False:
603 if self.cli_args.get('public_access') is False:
601 log.info('Public access disabled')
604 log.info('Public access disabled')
602 user.active = False
605 user.active = False
603 Session().add(user)
606 Session().add(user)
604 Session().commit()
607 Session().commit()
605
608
606 def create_permissions(self):
609 def create_permissions(self):
607 """
610 """
608 Creates all permissions defined in the system
611 Creates all permissions defined in the system
609 """
612 """
610 # module.(access|create|change|delete)_[name]
613 # module.(access|create|change|delete)_[name]
611 # module.(none|read|write|admin)
614 # module.(none|read|write|admin)
612 log.info('creating permissions')
615 log.info('creating permissions')
613 PermissionModel(self.sa).create_permissions()
616 PermissionModel(self.sa).create_permissions()
614
617
615 def populate_default_permissions(self):
618 def populate_default_permissions(self):
616 """
619 """
617 Populate default permissions. It will create only the default
620 Populate default permissions. It will create only the default
618 permissions that are missing, and not alter already defined ones
621 permissions that are missing, and not alter already defined ones
619 """
622 """
620 log.info('creating default user permissions')
623 log.info('creating default user permissions')
621 PermissionModel(self.sa).create_default_user_permissions(user=User.DEFAULT_USER)
624 PermissionModel(self.sa).create_default_user_permissions(user=User.DEFAULT_USER)
@@ -1,52 +1,55 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 import click
23 import click
24 import pyramid.paster
24 import pyramid.paster
25
25
26 from rhodecode.lib.pyramid_utils import bootstrap
26 from rhodecode.lib.pyramid_utils import bootstrap
27 from rhodecode.lib.db_manage import DbManage
27 from rhodecode.lib.db_manage import DbManage
28 from rhodecode.lib.utils2 import safe_int
28
29
29 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
30
31
31
32
32 @click.command()
33 @click.command()
33 @click.argument('ini_path', type=click.Path(exists=True))
34 @click.argument('ini_path', type=click.Path(exists=True))
34 @click.option('--force-yes/--force-no', default=None,
35 @click.option('--force-yes/--force-no', default=None,
35 help="Force yes/no to every question")
36 help="Force yes/no to every question")
36 def main(ini_path, force_yes):
37 @click.option('--force-version', default=None,
37 return command(ini_path, force_yes)
38 help="Force upgrade from version")
39 def main(ini_path, force_yes, force_version):
40 return command(ini_path, force_yes, force_version)
38
41
39
42
40 def command(ini_path, force_yes):
43 def command(ini_path, force_yes, force_version):
41 pyramid.paster.setup_logging(ini_path)
44 pyramid.paster.setup_logging(ini_path)
42
45
43 with bootstrap(ini_path, env={'RC_CMD_UPGRADE_DB': '1'}) as env:
46 with bootstrap(ini_path, env={'RC_CMD_UPGRADE_DB': '1'}) as env:
44 config = env['registry'].settings
47 config = env['registry'].settings
45 db_uri = config['sqlalchemy.db1.url']
48 db_uri = config['sqlalchemy.db1.url']
46 options = {}
49 options = {}
47 if force_yes is not None:
50 if force_yes is not None:
48 options['force_ask'] = force_yes
51 options['force_ask'] = force_yes
49 dbmanage = DbManage(
52 dbmanage = DbManage(
50 log_sql=True, dbconf=db_uri, root='.', tests=False,
53 log_sql=True, dbconf=db_uri, root='.', tests=False,
51 cli_args=options)
54 cli_args=options)
52 dbmanage.upgrade()
55 dbmanage.upgrade(version=safe_int(force_version))
General Comments 0
You need to be logged in to leave comments. Login now