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