##// END OF EJS Templates
fixed found issues in upgrade script
marcink -
r1987:77b5c24f beta
parent child Browse files
Show More
@@ -1,519 +1,520 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.db_manage
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Database creation, and setup module for RhodeCode. Used for creation
7 7 of database as well as for migration operations
8 8
9 9 :created_on: Apr 10, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import os
28 28 import sys
29 29 import uuid
30 30 import logging
31 31 from os.path import dirname as dn, join as jn
32 32
33 33 from rhodecode import __dbversion__
34 34 from rhodecode.model import meta
35 35
36 36 from rhodecode.model.user import UserModel
37 37 from rhodecode.lib.utils import ask_ok
38 38 from rhodecode.model import init_model
39 39 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
40 40 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup,\
41 41 UserRepoGroupToPerm
42 42
43 43 from sqlalchemy.engine import create_engine
44 44 from rhodecode.model.repos_group import ReposGroupModel
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class DbManage(object):
50 50 def __init__(self, log_sql, dbconf, root, tests=False):
51 51 self.dbname = dbconf.split('/')[-1]
52 52 self.tests = tests
53 53 self.root = root
54 54 self.dburi = dbconf
55 55 self.log_sql = log_sql
56 56 self.db_exists = False
57 57 self.init_db()
58 58
59 59 def init_db(self):
60 60 engine = create_engine(self.dburi, echo=self.log_sql)
61 61 init_model(engine)
62 62 self.sa = meta.Session
63 63
64 64 def create_tables(self, override=False):
65 65 """
66 66 Create a auth database
67 67 """
68 68
69 69 log.info("Any existing database is going to be destroyed")
70 70 if self.tests:
71 71 destroy = True
72 72 else:
73 73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
74 74 if not destroy:
75 75 sys.exit()
76 76 if destroy:
77 77 meta.Base.metadata.drop_all()
78 78
79 79 checkfirst = not override
80 80 meta.Base.metadata.create_all(checkfirst=checkfirst)
81 81 log.info('Created tables for %s' % self.dbname)
82 82
83 83 def set_db_version(self):
84 84 ver = DbMigrateVersion()
85 85 ver.version = __dbversion__
86 86 ver.repository_id = 'rhodecode_db_migrations'
87 87 ver.repository_path = 'versions'
88 88 self.sa.add(ver)
89 89 log.info('db version set to: %s' % __dbversion__)
90 90
91 91 def upgrade(self):
92 92 """
93 93 Upgrades given database schema to given revision following
94 94 all needed steps, to perform the upgrade
95 95
96 96 """
97 97
98 98 from rhodecode.lib.dbmigrate.migrate.versioning import api
99 99 from rhodecode.lib.dbmigrate.migrate.exceptions import \
100 100 DatabaseNotControlledError
101 101
102 102 if 'sqlite' in self.dburi:
103 103 print (
104 104 '********************** WARNING **********************\n'
105 105 'Make sure your version of sqlite is at least 3.7.X. \n'
106 106 'Earlier versions are known to fail on some migrations\n'
107 107 '*****************************************************\n'
108 108 )
109 109 upgrade = ask_ok('You are about to perform database upgrade, make '
110 110 'sure You backed up your database before. '
111 111 'Continue ? [y/n]')
112 112 if not upgrade:
113 113 sys.exit('Nothing done')
114 114
115 115 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
116 116 'rhodecode/lib/dbmigrate')
117 117 db_uri = self.dburi
118 118
119 119 try:
120 120 curr_version = api.db_version(db_uri, repository_path)
121 121 msg = ('Found current database under version'
122 122 ' control with version %s' % curr_version)
123 123
124 124 except (RuntimeError, DatabaseNotControlledError):
125 125 curr_version = 1
126 126 msg = ('Current database is not under version control. Setting'
127 127 ' as version %s' % curr_version)
128 128 api.version_control(db_uri, repository_path, curr_version)
129 129
130 130 print (msg)
131 131
132 132 if curr_version == __dbversion__:
133 133 sys.exit('This database is already at the newest version')
134 134
135 135 #======================================================================
136 136 # UPGRADE STEPS
137 137 #======================================================================
138 138 class UpgradeSteps(object):
139 139 """
140 140 Those steps follow schema versions so for example schema
141 141 for example schema with seq 002 == step_2 and so on.
142 142 """
143 143
144 144 def __init__(self, klass):
145 145 self.klass = klass
146 146
147 147 def step_0(self):
148 148 # step 0 is the schema upgrade, and than follow proper upgrades
149 149 print ('attempting to do database upgrade to version %s' \
150 150 % __dbversion__)
151 151 api.upgrade(db_uri, repository_path, __dbversion__)
152 152 print ('Schema upgrade completed')
153 153
154 154 def step_1(self):
155 155 pass
156 156
157 157 def step_2(self):
158 158 print ('Patching repo paths for newer version of RhodeCode')
159 159 self.klass.fix_repo_paths()
160 160
161 161 print ('Patching default user of RhodeCode')
162 162 self.klass.fix_default_user()
163 163
164 164 log.info('Changing ui settings')
165 165 self.klass.create_ui_settings()
166 166
167 167 def step_3(self):
168 168 print ('Adding additional settings into RhodeCode db')
169 169 self.klass.fix_settings()
170 170 print ('Adding ldap defaults')
171 171 self.klass.create_ldap_options(skip_existing=True)
172 172
173 173 def step_4(self):
174 174 print ('TODO:')
175 self.create_permissions()
175 self.klass.create_permissions()
176 176 self.klass.fixup_groups()
177 177
178 178 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
179 179
180 180 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
181 181 for step in upgrade_steps:
182 182 print ('performing upgrade step %s' % step)
183 183 getattr(UpgradeSteps(self), 'step_%s' % step)()
184
184 self.sa.commit()
185
185 186 def fix_repo_paths(self):
186 187 """
187 188 Fixes a old rhodecode version path into new one without a '*'
188 189 """
189 190
190 191 paths = self.sa.query(RhodeCodeUi)\
191 192 .filter(RhodeCodeUi.ui_key == '/')\
192 193 .scalar()
193 194
194 195 paths.ui_value = paths.ui_value.replace('*', '')
195 196
196 197 try:
197 198 self.sa.add(paths)
198 199 self.sa.commit()
199 200 except:
200 201 self.sa.rollback()
201 202 raise
202 203
203 204 def fix_default_user(self):
204 205 """
205 206 Fixes a old default user with some 'nicer' default values,
206 207 used mostly for anonymous access
207 208 """
208 209 def_user = self.sa.query(User)\
209 210 .filter(User.username == 'default')\
210 211 .one()
211 212
212 213 def_user.name = 'Anonymous'
213 214 def_user.lastname = 'User'
214 215 def_user.email = 'anonymous@rhodecode.org'
215 216
216 217 try:
217 218 self.sa.add(def_user)
218 219 self.sa.commit()
219 220 except:
220 221 self.sa.rollback()
221 222 raise
222 223
223 224 def fix_settings(self):
224 225 """
225 226 Fixes rhodecode settings adds ga_code key for google analytics
226 227 """
227 228
228 229 hgsettings3 = RhodeCodeSetting('ga_code', '')
229 230
230 231 try:
231 232 self.sa.add(hgsettings3)
232 233 self.sa.commit()
233 234 except:
234 235 self.sa.rollback()
235 236 raise
236 237
237 238 def admin_prompt(self, second=False):
238 239 if not self.tests:
239 240 import getpass
240 241
241 242 def get_password():
242 243 password = getpass.getpass('Specify admin password '
243 244 '(min 6 chars):')
244 245 confirm = getpass.getpass('Confirm password:')
245 246
246 247 if password != confirm:
247 248 log.error('passwords mismatch')
248 249 return False
249 250 if len(password) < 6:
250 251 log.error('password is to short use at least 6 characters')
251 252 return False
252 253
253 254 return password
254 255
255 256 username = raw_input('Specify admin username:')
256 257
257 258 password = get_password()
258 259 if not password:
259 260 #second try
260 261 password = get_password()
261 262 if not password:
262 263 sys.exit()
263 264
264 265 email = raw_input('Specify admin email:')
265 266 self.create_user(username, password, email, True)
266 267 else:
267 268 log.info('creating admin and regular test users')
268 269 from rhodecode.tests import TEST_USER_ADMIN_LOGIN,\
269 270 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL,\
270 271 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,\
271 272 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
272 273 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
273 274
274 275 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
275 276 TEST_USER_ADMIN_EMAIL, True)
276 277
277 278 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
278 279 TEST_USER_REGULAR_EMAIL, False)
279 280
280 281 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
281 282 TEST_USER_REGULAR2_EMAIL, False)
282 283
283 284 def create_ui_settings(self):
284 285 """
285 286 Creates ui settings, fills out hooks
286 287 and disables dotencode
287 288 """
288 289
289 290 #HOOKS
290 291 hooks1_key = RhodeCodeUi.HOOK_UPDATE
291 292 hooks1_ = self.sa.query(RhodeCodeUi)\
292 293 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
293 294
294 295 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
295 296 hooks1.ui_section = 'hooks'
296 297 hooks1.ui_key = hooks1_key
297 298 hooks1.ui_value = 'hg update >&2'
298 299 hooks1.ui_active = False
299 300
300 301 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
301 302 hooks2_ = self.sa.query(RhodeCodeUi)\
302 303 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
303 304
304 305 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
305 306 hooks2.ui_section = 'hooks'
306 307 hooks2.ui_key = hooks2_key
307 308 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
308 309
309 310 hooks3 = RhodeCodeUi()
310 311 hooks3.ui_section = 'hooks'
311 312 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
312 313 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
313 314
314 315 hooks4 = RhodeCodeUi()
315 316 hooks4.ui_section = 'hooks'
316 317 hooks4.ui_key = RhodeCodeUi.HOOK_PULL
317 318 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
318 319
319 320 # For mercurial 1.7 set backward comapatibility with format
320 321 dotencode_disable = RhodeCodeUi()
321 322 dotencode_disable.ui_section = 'format'
322 323 dotencode_disable.ui_key = 'dotencode'
323 324 dotencode_disable.ui_value = 'false'
324 325
325 326 # enable largefiles
326 327 largefiles = RhodeCodeUi()
327 328 largefiles.ui_section = 'extensions'
328 329 largefiles.ui_key = 'largefiles'
329 330 largefiles.ui_value = ''
330 331
331 332 self.sa.add(hooks1)
332 333 self.sa.add(hooks2)
333 334 self.sa.add(hooks3)
334 335 self.sa.add(hooks4)
335 336 self.sa.add(largefiles)
336 337
337 338 def create_ldap_options(self, skip_existing=False):
338 339 """Creates ldap settings"""
339 340
340 341 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
341 342 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
342 343 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
343 344 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
344 345 ('ldap_filter', ''), ('ldap_search_scope', ''),
345 346 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
346 347 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
347 348
348 349 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
349 350 log.debug('Skipping option %s' % k)
350 351 continue
351 352 setting = RhodeCodeSetting(k, v)
352 353 self.sa.add(setting)
353 354
354 355 def fixup_groups(self):
355 356 def_usr = User.get_by_username('default')
356 357 for g in RepoGroup.query().all():
357 358 g.group_name = g.get_new_name(g.name)
358 359 self.sa.add(g)
359 360 # get default perm
360 361 default = UserRepoGroupToPerm.query()\
361 362 .filter(UserRepoGroupToPerm.group == g)\
362 363 .filter(UserRepoGroupToPerm.user == def_usr)\
363 364 .scalar()
364 365
365 366 if default is None:
366 367 log.debug('missing default permission for group %s adding' % g)
367 368 ReposGroupModel()._create_default_perms(g)
368 369
369 370 def config_prompt(self, test_repo_path='', retries=3):
370 371 if retries == 3:
371 372 log.info('Setting up repositories config')
372 373
373 374 if not self.tests and not test_repo_path:
374 375 path = raw_input(
375 376 'Enter a valid path to store repositories. '
376 377 'All repositories in that path will be added automatically:'
377 378 )
378 379 else:
379 380 path = test_repo_path
380 381 path_ok = True
381 382
382 383 # check proper dir
383 384 if not os.path.isdir(path):
384 385 path_ok = False
385 386 log.error('Given path %s is not a valid directory' % path)
386 387
387 388 # check write access
388 389 if not os.access(path, os.W_OK) and path_ok:
389 390 path_ok = False
390 391 log.error('No write permission to given path %s' % path)
391 392
392 393 if retries == 0:
393 394 sys.exit('max retries reached')
394 395 if path_ok is False:
395 396 retries -= 1
396 397 return self.config_prompt(test_repo_path, retries)
397 398
398 399 return path
399 400
400 401 def create_settings(self, path):
401 402
402 403 self.create_ui_settings()
403 404
404 405 #HG UI OPTIONS
405 406 web1 = RhodeCodeUi()
406 407 web1.ui_section = 'web'
407 408 web1.ui_key = 'push_ssl'
408 409 web1.ui_value = 'false'
409 410
410 411 web2 = RhodeCodeUi()
411 412 web2.ui_section = 'web'
412 413 web2.ui_key = 'allow_archive'
413 414 web2.ui_value = 'gz zip bz2'
414 415
415 416 web3 = RhodeCodeUi()
416 417 web3.ui_section = 'web'
417 418 web3.ui_key = 'allow_push'
418 419 web3.ui_value = '*'
419 420
420 421 web4 = RhodeCodeUi()
421 422 web4.ui_section = 'web'
422 423 web4.ui_key = 'baseurl'
423 424 web4.ui_value = '/'
424 425
425 426 paths = RhodeCodeUi()
426 427 paths.ui_section = 'paths'
427 428 paths.ui_key = '/'
428 429 paths.ui_value = path
429 430
430 431 hgsettings1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
431 432 hgsettings2 = RhodeCodeSetting('title', 'RhodeCode')
432 433 hgsettings3 = RhodeCodeSetting('ga_code', '')
433 434
434 435 self.sa.add(web1)
435 436 self.sa.add(web2)
436 437 self.sa.add(web3)
437 438 self.sa.add(web4)
438 439 self.sa.add(paths)
439 440 self.sa.add(hgsettings1)
440 441 self.sa.add(hgsettings2)
441 442 self.sa.add(hgsettings3)
442 443
443 444 self.create_ldap_options()
444 445
445 446 log.info('created ui config')
446 447
447 448 def create_user(self, username, password, email='', admin=False):
448 449 log.info('creating user %s' % username)
449 450 UserModel().create_or_update(username, password, email,
450 451 name='RhodeCode', lastname='Admin',
451 452 active=True, admin=admin)
452 453
453 454 def create_default_user(self):
454 455 log.info('creating default user')
455 456 # create default user for handling default permissions.
456 457 UserModel().create_or_update(username='default',
457 458 password=str(uuid.uuid1())[:8],
458 459 email='anonymous@rhodecode.org',
459 460 name='Anonymous', lastname='User')
460 461
461 462 def create_permissions(self):
462 463 # module.(access|create|change|delete)_[name]
463 464 # module.(none|read|write|admin)
464 465 perms = [
465 466 ('repository.none', 'Repository no access'),
466 467 ('repository.read', 'Repository read access'),
467 468 ('repository.write', 'Repository write access'),
468 469 ('repository.admin', 'Repository admin access'),
469 470
470 471 ('group.none', 'Repositories Group no access'),
471 472 ('group.read', 'Repositories Group read access'),
472 473 ('group.write', 'Repositories Group write access'),
473 474 ('group.admin', 'Repositories Group admin access'),
474 475
475 476 ('hg.admin', 'Hg Administrator'),
476 477 ('hg.create.repository', 'Repository create'),
477 478 ('hg.create.none', 'Repository creation disabled'),
478 479 ('hg.register.none', 'Register disabled'),
479 480 ('hg.register.manual_activate', 'Register new user with RhodeCode '
480 481 'without manual activation'),
481 482
482 483 ('hg.register.auto_activate', 'Register new user with RhodeCode '
483 484 'without auto activation'),
484 485 ]
485 486
486 487 for p in perms:
487 if not Permission.get_by_key(p):
488 if not Permission.get_by_key(p[0]):
488 489 new_perm = Permission()
489 490 new_perm.permission_name = p[0]
490 491 new_perm.permission_longname = p[1]
491 492 self.sa.add(new_perm)
492 493
493 494 def populate_default_permissions(self):
494 495 log.info('creating default user permissions')
495 496
496 497 default_user = self.sa.query(User)\
497 498 .filter(User.username == 'default').scalar()
498 499
499 500 reg_perm = UserToPerm()
500 501 reg_perm.user = default_user
501 502 reg_perm.permission = self.sa.query(Permission)\
502 503 .filter(Permission.permission_name == 'hg.register.manual_activate')\
503 504 .scalar()
504 505
505 506 create_repo_perm = UserToPerm()
506 507 create_repo_perm.user = default_user
507 508 create_repo_perm.permission = self.sa.query(Permission)\
508 509 .filter(Permission.permission_name == 'hg.create.repository')\
509 510 .scalar()
510 511
511 512 default_repo_perm = UserToPerm()
512 513 default_repo_perm.user = default_user
513 514 default_repo_perm.permission = self.sa.query(Permission)\
514 515 .filter(Permission.permission_name == 'repository.read')\
515 516 .scalar()
516 517
517 518 self.sa.add(reg_perm)
518 519 self.sa.add(create_repo_perm)
519 520 self.sa.add(default_repo_perm)
General Comments 0
You need to be logged in to leave comments. Login now