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