##// END OF EJS Templates
core: ported setup-app to pyramid command....
marcink -
r2341:31bf5a7b default
parent child Browse files
Show More
@@ -1,33 +1,103 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 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 import logging
20 21
21 22 import click
23 import pyramid.paster
22 24
23 from rhodecode.lib.pyramid_utils import bootstrap
24 import pyramid.paster
25 from rhodecode.lib.pyramid_utils import bootstrap, get_app_config
26 from rhodecode.lib.db_manage import DbManage
27 from rhodecode.model.db import Session
28
29
30 log = logging.getLogger(__name__)
25 31
26 32
27 33 @click.command()
28 34 @click.argument('ini_path', type=click.Path(exists=True))
29 def main(ini_path):
35 @click.option(
36 '--force-yes/--force-no', default=None,
37 help="Force yes/no to every question")
38 @click.option(
39 '--user',
40 default=None,
41 help='Initial super-admin username')
42 @click.option(
43 '--email',
44 default=None,
45 help='Initial super-admin email address.')
46 @click.option(
47 '--password',
48 default=None,
49 help='Initial super-admin password. Minimum 6 chars.')
50 @click.option(
51 '--api-key',
52 help='Initial API key for the admin user')
53 @click.option(
54 '--repos',
55 default=None,
56 help='Absolute path to storage location. This is storage for all '
57 'existing and future repositories, and repository groups.')
58 @click.option(
59 '--public-access/--no-public-access',
60 default=None,
61 help='Enable public access on this installation. '
62 'Default is public access enabled.')
63 def main(ini_path, force_yes, user, email, password, api_key, repos,
64 public_access):
65 return command(ini_path, force_yes, user, email, password, api_key,
66 repos, public_access)
67
68
69 def command(ini_path, force_yes, user, email, password, api_key, repos,
70 public_access):
71 # mapping of old parameters to new CLI from click
72 options = dict(
73 username=user,
74 email=email,
75 password=password,
76 api_key=api_key,
77 repos_location=repos,
78 force_ask=force_yes,
79 public_access=public_access
80 )
30 81 pyramid.paster.setup_logging(ini_path)
31 82
83 config = get_app_config(ini_path)
84
85 db_uri = config['sqlalchemy.db1.url']
86 dbmanage = DbManage(log_sql=True, dbconf=db_uri, root='.',
87 tests=False, cli_args=options)
88 dbmanage.create_tables(override=True)
89 dbmanage.set_db_version()
90 opts = dbmanage.config_prompt(None)
91 dbmanage.create_settings(opts)
92 dbmanage.create_default_user()
93 dbmanage.create_admin_and_prompt()
94 dbmanage.create_permissions()
95 dbmanage.populate_default_permissions()
96 Session().commit()
97
32 98 with bootstrap(ini_path) as env:
33 print(env['request'].application_url) No newline at end of file
99 msg = 'Successfully initialized database, schema and default data.'
100 print()
101 print('*' * len(msg))
102 print(msg.upper())
103 print('*' * len(msg))
@@ -1,287 +1,287 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 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 from subprocess32 import Popen, PIPE
22 22 import os
23 23 import shutil
24 24 import sys
25 25 import tempfile
26 26
27 27 import pytest
28 28 from sqlalchemy.engine import url
29 29
30 30 from rhodecode.tests.fixture import TestINI
31 31
32 32
33 33 def _get_dbs_from_metafunc(metafunc):
34 34 if hasattr(metafunc.function, 'dbs'):
35 35 # Supported backends by this test function, created from
36 36 # pytest.mark.dbs
37 37 backends = metafunc.function.dbs.args
38 38 else:
39 39 backends = metafunc.config.getoption('--dbs')
40 40 return backends
41 41
42 42
43 43 def pytest_generate_tests(metafunc):
44 44 # Support test generation based on --dbs parameter
45 45 if 'db_backend' in metafunc.fixturenames:
46 46 requested_backends = set(metafunc.config.getoption('--dbs'))
47 47 backends = _get_dbs_from_metafunc(metafunc)
48 48 backends = requested_backends.intersection(backends)
49 49 # TODO: johbo: Disabling a backend did not work out with
50 50 # parametrization, find better way to achieve this.
51 51 if not backends:
52 52 metafunc.function._skip = True
53 53 metafunc.parametrize('db_backend_name', backends)
54 54
55 55
56 56 def pytest_collection_modifyitems(session, config, items):
57 57 remaining = [
58 58 i for i in items if not getattr(i.obj, '_skip', False)]
59 59 items[:] = remaining
60 60
61 61
62 62 @pytest.fixture
63 63 def db_backend(
64 64 request, db_backend_name, pylons_config, tmpdir_factory):
65 65 basetemp = tmpdir_factory.getbasetemp().strpath
66 66 klass = _get_backend(db_backend_name)
67 67
68 68 option_name = '--{}-connection-string'.format(db_backend_name)
69 69 connection_string = request.config.getoption(option_name) or None
70 70
71 71 return klass(
72 72 config_file=pylons_config, basetemp=basetemp,
73 73 connection_string=connection_string)
74 74
75 75
76 76 def _get_backend(backend_type):
77 77 return {
78 78 'sqlite': SQLiteDBBackend,
79 79 'postgres': PostgresDBBackend,
80 80 'mysql': MySQLDBBackend,
81 81 '': EmptyDBBackend
82 82 }[backend_type]
83 83
84 84
85 85 class DBBackend(object):
86 86 _store = os.path.dirname(os.path.abspath(__file__))
87 87 _type = None
88 88 _base_ini_config = [{'app:main': {'vcs.start_server': 'false'}}]
89 89 _db_url = [{'app:main': {'sqlalchemy.db1.url': ''}}]
90 90 _base_db_name = 'rhodecode_test_db_backend'
91 91
92 92 def __init__(
93 93 self, config_file, db_name=None, basetemp=None,
94 94 connection_string=None):
95 95
96 96 from rhodecode.lib.vcs.backends.hg import largefiles_store
97 97 from rhodecode.lib.vcs.backends.git import lfs_store
98 98
99 99 self.fixture_store = os.path.join(self._store, self._type)
100 100 self.db_name = db_name or self._base_db_name
101 101 self._base_ini_file = config_file
102 102 self.stderr = ''
103 103 self.stdout = ''
104 104 self._basetemp = basetemp or tempfile.gettempdir()
105 105 self._repos_location = os.path.join(self._basetemp, 'rc_test_repos')
106 106 self._repos_hg_largefiles_store = largefiles_store(self._basetemp)
107 107 self._repos_git_lfs_store = lfs_store(self._basetemp)
108 108 self.connection_string = connection_string
109 109
110 110 @property
111 111 def connection_string(self):
112 112 return self._connection_string
113 113
114 114 @connection_string.setter
115 115 def connection_string(self, new_connection_string):
116 116 if not new_connection_string:
117 117 new_connection_string = self.get_default_connection_string()
118 118 else:
119 119 new_connection_string = new_connection_string.format(
120 120 db_name=self.db_name)
121 121 url_parts = url.make_url(new_connection_string)
122 122 self._connection_string = new_connection_string
123 123 self.user = url_parts.username
124 124 self.password = url_parts.password
125 125 self.host = url_parts.host
126 126
127 127 def get_default_connection_string(self):
128 128 raise NotImplementedError('default connection_string is required.')
129 129
130 130 def execute(self, cmd, env=None, *args):
131 131 """
132 132 Runs command on the system with given ``args``.
133 133 """
134 134
135 135 command = cmd + ' ' + ' '.join(args)
136 136 sys.stdout.write(command)
137 137
138 138 # Tell Python to use UTF-8 encoding out stdout
139 139 _env = os.environ.copy()
140 140 _env['PYTHONIOENCODING'] = 'UTF-8'
141 141 if env:
142 142 _env.update(env)
143 143 self.p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, env=_env)
144 144 self.stdout, self.stderr = self.p.communicate()
145 145 sys.stdout.write('COMMAND:'+command+'\n')
146 146 sys.stdout.write(self.stdout)
147 147 return self.stdout, self.stderr
148 148
149 149 def assert_returncode_success(self):
150 150 if not self.p.returncode == 0:
151 151 print(self.stderr)
152 152 raise AssertionError('non 0 retcode:{}'.format(self.p.returncode))
153 153
154 154 def setup_rhodecode_db(self, ini_params=None, env=None):
155 155 if not ini_params:
156 156 ini_params = self._base_ini_config
157 157
158 158 ini_params.extend(self._db_url)
159 159 with TestINI(self._base_ini_file, ini_params,
160 160 self._type, destroy=True) as _ini_file:
161 161
162 162 if not os.path.isdir(self._repos_location):
163 163 os.makedirs(self._repos_location)
164 164 if not os.path.isdir(self._repos_hg_largefiles_store):
165 165 os.makedirs(self._repos_hg_largefiles_store)
166 166 if not os.path.isdir(self._repos_git_lfs_store):
167 167 os.makedirs(self._repos_git_lfs_store)
168 168
169 169 self.execute(
170 "paster setup-rhodecode {0} --user=marcink "
170 "rc-setup-app {0} --user=marcink "
171 171 "--email=marcin@rhodeocode.com --password={1} "
172 172 "--repos={2} --force-yes".format(
173 173 _ini_file, 'qweqwe', self._repos_location), env=env)
174 174
175 175 def upgrade_database(self, ini_params=None):
176 176 if not ini_params:
177 177 ini_params = self._base_ini_config
178 178 ini_params.extend(self._db_url)
179 179
180 180 test_ini = TestINI(
181 181 self._base_ini_file, ini_params, self._type, destroy=True)
182 182 with test_ini as ini_file:
183 183 if not os.path.isdir(self._repos_location):
184 184 os.makedirs(self._repos_location)
185 185 self.execute(
186 186 "paster upgrade-db {} --force-yes".format(ini_file))
187 187
188 188 def setup_db(self):
189 189 raise NotImplementedError
190 190
191 191 def teardown_db(self):
192 192 raise NotImplementedError
193 193
194 194 def import_dump(self, dumpname):
195 195 raise NotImplementedError
196 196
197 197
198 198 class EmptyDBBackend(DBBackend):
199 199 _type = ''
200 200
201 201 def setup_db(self):
202 202 pass
203 203
204 204 def teardown_db(self):
205 205 pass
206 206
207 207 def import_dump(self, dumpname):
208 208 pass
209 209
210 210 def assert_returncode_success(self):
211 211 assert True
212 212
213 213
214 214 class SQLiteDBBackend(DBBackend):
215 215 _type = 'sqlite'
216 216
217 217 def get_default_connection_string(self):
218 218 return 'sqlite:///{}/{}.sqlite'.format(self._basetemp, self.db_name)
219 219
220 220 def setup_db(self):
221 221 # dump schema for tests
222 222 # cp -v $TEST_DB_NAME
223 223 self._db_url = [{'app:main': {
224 224 'sqlalchemy.db1.url': self.connection_string}}]
225 225
226 226 def import_dump(self, dumpname):
227 227 dump = os.path.join(self.fixture_store, dumpname)
228 228 shutil.copy(
229 229 dump,
230 230 os.path.join(self._basetemp, '{0.db_name}.sqlite'.format(self)))
231 231
232 232 def teardown_db(self):
233 233 self.execute("rm -rf {}.sqlite".format(
234 234 os.path.join(self._basetemp, self.db_name)))
235 235
236 236
237 237 class MySQLDBBackend(DBBackend):
238 238 _type = 'mysql'
239 239
240 240 def get_default_connection_string(self):
241 241 return 'mysql://root:qweqwe@127.0.0.1/{}'.format(self.db_name)
242 242
243 243 def setup_db(self):
244 244 # dump schema for tests
245 245 # mysqldump -uroot -pqweqwe $TEST_DB_NAME
246 246 self._db_url = [{'app:main': {
247 247 'sqlalchemy.db1.url': self.connection_string}}]
248 248 self.execute("mysql -v -u{} -p{} -e 'create database '{}';'".format(
249 249 self.user, self.password, self.db_name))
250 250
251 251 def import_dump(self, dumpname):
252 252 dump = os.path.join(self.fixture_store, dumpname)
253 253 self.execute("mysql -u{} -p{} {} < {}".format(
254 254 self.user, self.password, self.db_name, dump))
255 255
256 256 def teardown_db(self):
257 257 self.execute("mysql -v -u{} -p{} -e 'drop database '{}';'".format(
258 258 self.user, self.password, self.db_name))
259 259
260 260
261 261 class PostgresDBBackend(DBBackend):
262 262 _type = 'postgres'
263 263
264 264 def get_default_connection_string(self):
265 265 return 'postgresql://postgres:qweqwe@localhost/{}'.format(self.db_name)
266 266
267 267 def setup_db(self):
268 268 # dump schema for tests
269 269 # pg_dump -U postgres -h localhost $TEST_DB_NAME
270 270 self._db_url = [{'app:main': {
271 271 'sqlalchemy.db1.url':
272 272 self.connection_string}}]
273 273 self.execute("PGPASSWORD={} psql -U {} -h localhost "
274 274 "-c 'create database '{}';'".format(
275 275 self.password, self.user, self.db_name))
276 276
277 277 def teardown_db(self):
278 278 self.execute("PGPASSWORD={} psql -U {} -h localhost "
279 279 "-c 'drop database if exists '{}';'".format(
280 280 self.password, self.user, self.db_name))
281 281
282 282 def import_dump(self, dumpname):
283 283 dump = os.path.join(self.fixture_store, dumpname)
284 284 self.execute(
285 285 "PGPASSWORD={} psql -U {} -h localhost -d {} -1 "
286 286 "-f {}".format(
287 287 self.password, self.user, self.db_name, dump))
@@ -1,17 +1,17 b''
1 1 #!/bin/sh
2 2 psql -U postgres -h localhost -c 'drop database if exists rhodecode;'
3 3 psql -U postgres -h localhost -c 'create database rhodecode;'
4 paster setup-rhodecode rc.ini --force-yes --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos --no-public-access
4 rc-setup-app rc.ini --force-yes --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos --no-public-access
5 5 API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d rhodecode | awk '{print $2}'`
6 6 echo "run those after running server"
7 7 paster serve rc.ini --pid-file=rc.pid --daemon
8 8 sleep 3
9 9 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@rhodecode.org
10 10 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org
11 11 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@rhodecode.org
12 12 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
13 13 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
14 14 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
15 15 echo "killing server"
16 16 kill `cat rc.pid`
17 17 rm rc.pid
@@ -1,49 +1,44 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 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 """
22 Weboperations and setup for rhodecode
23 """
24 21
25 22 import logging
26 23
27 from rhodecode.config.environment import load_environment
28 from rhodecode.lib.db_manage import DbManage
29 from rhodecode.model.meta import Session
30
24 from rhodecode.lib.rc_commands.setup_rc import command as setup_command
31 25
32 26 log = logging.getLogger(__name__)
33 27
34 28
35 29 def setup_app(command, conf, vars):
36 """Place any commands to setup rhodecode here"""
37 dbconf = conf['sqlalchemy.db1.url']
38 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
39 tests=False, cli_args=command.options.__dict__)
40 dbmanage.create_tables(override=True)
41 dbmanage.set_db_version()
42 opts = dbmanage.config_prompt(None)
43 dbmanage.create_settings(opts)
44 dbmanage.create_default_user()
45 dbmanage.create_admin_and_prompt()
46 dbmanage.create_permissions()
47 dbmanage.populate_default_permissions()
48 Session().commit()
49 load_environment(conf.global_conf, conf.local_conf, initial=True)
30 opts = command.options.__dict__
31
32 # mapping of old parameters to new CLI from click
33 options = dict(
34 ini_path=command.args[0],
35 force_yes=opts.get('force_ask'),
36 user=opts.get('username'),
37 email=opts.get('email'),
38 password=opts.get('password'),
39 api_key=opts.get('api_key'),
40 repos=opts.get('repos_location'),
41 public_access=opts.get('public_access')
42 )
43 setup_command(**options)
44
General Comments 0
You need to be logged in to leave comments. Login now