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