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