##// END OF EJS Templates
db: introduce db-create --reuse option...
Mads Kiilerich -
r8340:307c876a default
parent child Browse files
Show More
@@ -1,685 +1,694 b''
1 1 .. _setup:
2 2
3 3 =====
4 4 Setup
5 5 =====
6 6
7 7
8 8 Setting up Kallithea
9 9 --------------------
10 10
11 11 Some further details to the steps mentioned in the overview.
12 12
13 13 Create low level configuration file
14 14 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15 15
16 16 First, you will need to create a Kallithea configuration file. The
17 17 configuration file is a ``.ini`` file that contains various low level settings
18 18 for Kallithea, e.g. configuration of how to use database, web server, email,
19 19 and logging.
20 20
21 21 Run the following command to create the file ``my.ini`` in the current
22 22 directory::
23 23
24 24 kallithea-cli config-create my.ini http_server=waitress
25 25
26 26 To get a good starting point for your configuration, specify the http server
27 27 you intend to use. It can be ``waitress``, ``gearbox``, ``gevent``,
28 28 ``gunicorn``, or ``uwsgi``. (Apache ``mod_wsgi`` will not use this
29 29 configuration file, and it is fine to keep the default http_server configuration
30 30 unused. ``mod_wsgi`` is configured using ``httpd.conf`` directives and a WSGI
31 31 wrapper script.)
32 32
33 33 Extra custom settings can be specified like::
34 34
35 35 kallithea-cli config-create my.ini host=8.8.8.8 "[handler_console]" formatter=color_formatter
36 36
37 37 Populate the database
38 38 ^^^^^^^^^^^^^^^^^^^^^
39 39
40 40 Next, you need to create the databases used by Kallithea. Kallithea currently
41 41 supports PostgreSQL, SQLite and MariaDB/MySQL databases. It is recommended to
42 42 start out using SQLite (the default) and move to PostgreSQL if it becomes a
43 43 bottleneck or to get a "proper" database. MariaDB/MySQL is also supported.
44 44
45 45 For PostgreSQL, run ``pip install psycopg2`` to get the database driver. Make
46 46 sure the PostgreSQL server is initialized and running. Make sure you have a
47 47 database user with password authentication with permissions to create databases
48 48 - for example by running::
49 49
50 50 sudo -u postgres createuser 'kallithea' --pwprompt --createdb
51 51
52 52 For MariaDB/MySQL, run ``pip install mysqlclient`` to get the ``MySQLdb``
53 53 database driver. Make sure the database server is initialized and running. Make
54 54 sure you have a database user with password authentication with permissions to
55 55 create the database - for example by running::
56 56
57 57 echo 'CREATE USER "kallithea"@"localhost" IDENTIFIED BY "password"' | sudo -u mysql mysql
58 58 echo 'GRANT ALL PRIVILEGES ON `kallithea`.* TO "kallithea"@"localhost"' | sudo -u mysql mysql
59 59
60 60 Check and adjust ``sqlalchemy.url`` in your ``my.ini`` configuration file to use
61 61 this database.
62 62
63 63 Create the database, tables, and initial content by running the following
64 64 command::
65 65
66 66 kallithea-cli db-create -c my.ini
67 67
68 68 This will first prompt you for a "root" path. This "root" path is the location
69 69 where Kallithea will store all of its repositories on the current machine. This
70 70 location must be writable for the running Kallithea application. Next,
71 71 ``db-create`` will prompt you for a username and password for the initial admin
72 72 account it sets up for you.
73 73
74 74 The ``db-create`` values can also be given on the command line.
75 75 Example::
76 76
77 77 kallithea-cli db-create -c my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
78 78
79 79 The ``db-create`` command will create all needed tables and an
80 80 admin account. When choosing a root path you can either use a new
81 81 empty location, or a location which already contains existing
82 82 repositories. If you choose a location which contains existing
83 83 repositories Kallithea will add all of the repositories at the chosen
84 84 location to its database. (Note: make sure you specify the correct
85 85 path to the root).
86 86
87 .. note:: It is also possible to use an existing database. For example,
88 when using PostgreSQL without granting general createdb privileges to
89 the PostgreSQL kallithea user, set ``sqlalchemy.url =
90 postgresql://kallithea:password@localhost/kallithea`` and create the
91 database like::
92
93 sudo -u postgres createdb 'kallithea' --owner 'kallithea'
94 kallithea-cli db-create -c my.ini --reuse
95
87 96 Prepare front-end files
88 97 ^^^^^^^^^^^^^^^^^^^^^^^
89 98
90 99 Finally, the front-end files must be prepared. This requires ``npm`` version 6
91 100 or later, which needs ``node.js`` (version 12 or later). Prepare the front-end
92 101 by running::
93 102
94 103 kallithea-cli front-end-build
95 104
96 105 Running
97 106 ^^^^^^^
98 107
99 108 You are now ready to use Kallithea. To run it using a gearbox web server,
100 109 simply execute::
101 110
102 111 gearbox serve -c my.ini
103 112
104 113 - This command runs the Kallithea server. The web app should be available at
105 114 http://127.0.0.1:5000. The IP address and port is configurable via the
106 115 configuration file created in the previous step.
107 116 - Log in to Kallithea using the admin account created when running ``db-create``.
108 117 - The default permissions on each repository is read, and the owner is admin.
109 118 Remember to update these if needed.
110 119 - In the admin panel you can toggle LDAP, anonymous, and permissions
111 120 settings, as well as edit more advanced options on users and
112 121 repositories.
113 122
114 123
115 124 Internationalization (i18n support)
116 125 -----------------------------------
117 126
118 127 The Kallithea web interface is automatically displayed in the user's preferred
119 128 language, as indicated by the browser. Thus, different users may see the
120 129 application in different languages. If the requested language is not available
121 130 (because the translation file for that language does not yet exist or is
122 131 incomplete), English is used.
123 132
124 133 If you want to disable automatic language detection and instead configure a
125 134 fixed language regardless of user preference, set ``i18n.enabled = false`` and
126 135 specify another language by setting ``i18n.lang`` in the Kallithea
127 136 configuration file.
128 137
129 138
130 139 Using Kallithea with SSH
131 140 ------------------------
132 141
133 142 Kallithea supports repository access via SSH key based authentication.
134 143 This means:
135 144
136 145 - repository URLs like ``ssh://kallithea@example.com/name/of/repository``
137 146
138 147 - all network traffic for both read and write happens over the SSH protocol on
139 148 port 22, without using HTTP/HTTPS nor the Kallithea WSGI application
140 149
141 150 - encryption and authentication protocols are managed by the system's ``sshd``
142 151 process, with all users using the same Kallithea system user (e.g.
143 152 ``kallithea``) when connecting to the SSH server, but with users' public keys
144 153 in the Kallithea system user's `.ssh/authorized_keys` file granting each user
145 154 sandboxed access to the repositories.
146 155
147 156 - users and admins can manage SSH public keys in the web UI
148 157
149 158 - in their SSH client configuration, users can configure how the client should
150 159 control access to their SSH key - without passphrase, with passphrase, and
151 160 optionally with passphrase caching in the local shell session (``ssh-agent``).
152 161 This is standard SSH functionality, not something Kallithea provides or
153 162 interferes with.
154 163
155 164 - network communication between client and server happens in a bidirectional
156 165 stateful stream, and will in some cases be faster than HTTP/HTTPS with several
157 166 stateless round-trips.
158 167
159 168 .. note:: At this moment, repository access via SSH has been tested on Unix
160 169 only. Windows users that care about SSH are invited to test it and report
161 170 problems, ideally contributing patches that solve these problems.
162 171
163 172 Users and admins can upload SSH public keys (e.g. ``.ssh/id_rsa.pub``) through
164 173 the web interface. The server's ``.ssh/authorized_keys`` file is automatically
165 174 maintained with an entry for each SSH key. Each entry will tell ``sshd`` to run
166 175 ``kallithea-cli`` with the ``ssh-serve`` sub-command and the right Kallithea user ID
167 176 when encountering the corresponding SSH key.
168 177
169 178 To enable SSH repository access, Kallithea must be configured with the path to
170 179 the ``.ssh/authorized_keys`` file for the Kallithea user, and the path to the
171 180 ``kallithea-cli`` command. Put something like this in the ``.ini`` file::
172 181
173 182 ssh_enabled = true
174 183 ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
175 184 kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
176 185
177 186 The SSH service must be running, and the Kallithea user account must be active
178 187 (not necessarily with password access, but public key access must be enabled),
179 188 all file permissions must be set as sshd wants it, and ``authorized_keys`` must
180 189 be writeable by the Kallithea user.
181 190
182 191 .. note:: The ``authorized_keys`` file will be rewritten from scratch on
183 192 each update. If it already exists with other data, Kallithea will not
184 193 overwrite the existing ``authorized_keys``, and the server process will
185 194 instead throw an exception. The system administrator thus cannot ssh
186 195 directly to the Kallithea user but must use su/sudo from another account.
187 196
188 197 If ``/home/kallithea/.ssh/`` (the directory of the path specified in the
189 198 ``ssh_authorized_keys`` setting of the ``.ini`` file) does not exist as a
190 199 directory, Kallithea will attempt to create it. If that path exists but is
191 200 *not* a directory, or is not readable-writable-executable by the server
192 201 process, the server process will raise an exception each time it attempts to
193 202 write the ``authorized_keys`` file.
194 203
195 204 .. note:: It is possible to configure the SSH server to look for authorized
196 205 keys in multiple files, for example reserving ``ssh/authorized_keys`` to be
197 206 used for normal SSH and with Kallithea using
198 207 ``.ssh/authorized_keys_kallithea``. In ``/etc/ssh/sshd_config`` set
199 208 ``AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys_kallithea``
200 209 and restart sshd, and in ``my.ini`` set ``ssh_authorized_keys =
201 210 /home/kallithea/.ssh/authorized_keys_kallithea``. Note that this new
202 211 location will apply to all system users, and that multiple entries for the
203 212 same SSH key will shadow each other.
204 213
205 214 .. warning:: The handling of SSH access is steered directly by the command
206 215 specified in the ``authorized_keys`` file. There is no interaction with the
207 216 web UI. Once SSH access is correctly configured and enabled, it will work
208 217 regardless of whether the Kallithea web process is actually running. Hence,
209 218 if you want to perform repository or server maintenance and want to fully
210 219 disable all access to the repositories, disable SSH access by setting
211 220 ``ssh_enabled = false`` in the correct ``.ini`` file (i.e. the ``.ini`` file
212 221 specified in the ``authorized_keys`` file.)
213 222
214 223 The ``authorized_keys`` file can be updated manually with ``kallithea-cli
215 224 ssh-update-authorized-keys -c my.ini``. This command is not needed in normal
216 225 operation but is for example useful after changing SSH-related settings in the
217 226 ``.ini`` file or renaming that file. (The path to the ``.ini`` file is used in
218 227 the generated ``authorized_keys`` file).
219 228
220 229
221 230 Setting up Whoosh full text search
222 231 ----------------------------------
223 232
224 233 Kallithea provides full text search of repositories using `Whoosh`__.
225 234
226 235 .. __: https://whoosh.readthedocs.io/en/latest/
227 236
228 237 For an incremental index build, run::
229 238
230 239 kallithea-cli index-create -c my.ini
231 240
232 241 For a full index rebuild, run::
233 242
234 243 kallithea-cli index-create -c my.ini --full
235 244
236 245 The ``--repo-location`` option allows the location of the repositories to be overridden;
237 246 usually, the location is retrieved from the Kallithea database.
238 247
239 248 The ``--index-only`` option can be used to limit the indexed repositories to a comma-separated list::
240 249
241 250 kallithea-cli index-create -c my.ini --index-only=vcs,kallithea
242 251
243 252 To keep your index up-to-date it is necessary to do periodic index builds;
244 253 for this, it is recommended to use a crontab entry. Example::
245 254
246 255 0 3 * * * /path/to/virtualenv/bin/kallithea-cli index-create -c /path/to/kallithea/my.ini
247 256
248 257 When using incremental mode (the default), Whoosh will check the last
249 258 modification date of each file and add it to be reindexed if a newer file is
250 259 available. The indexing daemon checks for any removed files and removes them
251 260 from index.
252 261
253 262 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
254 263 or in the admin panel you can check the "build from scratch" checkbox.
255 264
256 265
257 266 Integration with issue trackers
258 267 -------------------------------
259 268
260 269 Kallithea provides a simple integration with issue trackers. It's possible
261 270 to define a regular expression that will match an issue ID in commit messages,
262 271 and have that replaced with a URL to the issue.
263 272
264 273 This is achieved with following three variables in the ini file::
265 274
266 275 issue_pat = #(\d+)
267 276 issue_server_link = https://issues.example.com/{repo}/issue/\1
268 277 issue_sub =
269 278
270 279 ``issue_pat`` is the regular expression describing which strings in
271 280 commit messages will be treated as issue references. The expression can/should
272 281 have one or more parenthesized groups that can later be referred to in
273 282 ``issue_server_link`` and ``issue_sub`` (see below). If you prefer, named groups
274 283 can be used instead of simple parenthesized groups.
275 284
276 285 If the pattern should only match if it is preceded by whitespace, add the
277 286 following string before the actual pattern: ``(?:^|(?<=\s))``.
278 287 If the pattern should only match if it is followed by whitespace, add the
279 288 following string after the actual pattern: ``(?:$|(?=\s))``.
280 289 These expressions use lookbehind and lookahead assertions of the Python regular
281 290 expression module to avoid the whitespace to be part of the actual pattern,
282 291 otherwise the link text will also contain that whitespace.
283 292
284 293 Matched issue references are replaced with the link specified in
285 294 ``issue_server_link``, in which any backreferences are resolved. Backreferences
286 295 can be ``\1``, ``\2``, ... or for named groups ``\g<groupname>``.
287 296 The special token ``{repo}`` is replaced with the full repository path
288 297 (including repository groups), while token ``{repo_name}`` is replaced with the
289 298 repository name (without repository groups).
290 299
291 300 The link text is determined by ``issue_sub``, which can be a string containing
292 301 backreferences to the groups specified in ``issue_pat``. If ``issue_sub`` is
293 302 empty, then the text matched by ``issue_pat`` is used verbatim.
294 303
295 304 The example settings shown above match issues in the format ``#<number>``.
296 305 This will cause the text ``#300`` to be transformed into a link:
297 306
298 307 .. code-block:: html
299 308
300 309 <a href="https://issues.example.com/example_repo/issue/300">#300</a>
301 310
302 311 The following example transforms a text starting with either of 'pullrequest',
303 312 'pull request' or 'PR', followed by an optional space, then a pound character
304 313 (#) and one or more digits, into a link with the text 'PR #' followed by the
305 314 digits::
306 315
307 316 issue_pat = (pullrequest|pull request|PR) ?#(\d+)
308 317 issue_server_link = https://issues.example.com/\2
309 318 issue_sub = PR #\2
310 319
311 320 The following example demonstrates how to require whitespace before the issue
312 321 reference in order for it to be recognized, such that the text ``issue#123`` will
313 322 not cause a match, but ``issue #123`` will::
314 323
315 324 issue_pat = (?:^|(?<=\s))#(\d+)
316 325 issue_server_link = https://issues.example.com/\1
317 326 issue_sub =
318 327
319 328 If needed, more than one pattern can be specified by appending a unique suffix to
320 329 the variables. For example, also demonstrating the use of named groups::
321 330
322 331 issue_pat_wiki = wiki-(?P<pagename>\S+)
323 332 issue_server_link_wiki = https://wiki.example.com/\g<pagename>
324 333 issue_sub_wiki = WIKI-\g<pagename>
325 334
326 335 With these settings, wiki pages can be referenced as wiki-some-id, and every
327 336 such reference will be transformed into:
328 337
329 338 .. code-block:: html
330 339
331 340 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
332 341
333 342 Refer to the `Python regular expression documentation`_ for more details about
334 343 the supported syntax in ``issue_pat``, ``issue_server_link`` and ``issue_sub``.
335 344
336 345
337 346 Hook management
338 347 ---------------
339 348
340 349 Hooks can be managed in similar way to that used in ``.hgrc`` files.
341 350 To manage hooks, choose *Admin > Settings > Hooks*.
342 351
343 352 The built-in hooks cannot be modified, though they can be enabled or disabled in the *VCS* section.
344 353
345 354 To add another custom hook simply fill in the first textbox with
346 355 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
347 356 can be found in ``kallithea.lib.hooks``.
348 357
349 358
350 359 Changing default encoding
351 360 -------------------------
352 361
353 362 By default, Kallithea uses UTF-8 encoding.
354 363 This is configurable as ``default_encoding`` in the .ini file.
355 364 This affects many parts in Kallithea including user names, filenames, and
356 365 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
357 366 library is installed. If ``chardet`` is detected Kallithea will fallback to it
358 367 when there are encode/decode errors.
359 368
360 369 The Mercurial encoding is configurable as ``hgencoding``. It is similar to
361 370 setting the ``HGENCODING`` environment variable, but will override it.
362 371
363 372
364 373 Celery configuration
365 374 --------------------
366 375
367 376 Kallithea can use the distributed task queue system Celery_ to run tasks like
368 377 cloning repositories or sending emails.
369 378
370 379 Kallithea will in most setups work perfectly fine out of the box (without
371 380 Celery), executing all tasks in the web server process. Some tasks can however
372 381 take some time to run and it can be better to run such tasks asynchronously in
373 382 a separate process so the web server can focus on serving web requests.
374 383
375 384 For installation and configuration of Celery, see the `Celery documentation`_.
376 385 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
377 386 or Redis_.
378 387
379 388 The use of Celery is configured in the Kallithea ini configuration file.
380 389 To enable it, simply set::
381 390
382 391 use_celery = true
383 392
384 393 and add or change the ``celery.*`` configuration variables.
385 394
386 395 Configuration settings are prefixed with 'celery.', so for example setting
387 396 `broker_url` in Celery means setting `celery.broker_url` in the configuration
388 397 file.
389 398
390 399 To start the Celery process, run::
391 400
392 401 kallithea-cli celery-run -c my.ini
393 402
394 403 Extra options to the Celery worker can be passed after ``--`` - see ``-- -h``
395 404 for more info.
396 405
397 406 .. note::
398 407 Make sure you run this command from the same virtualenv, and with the same
399 408 user that Kallithea runs.
400 409
401 410
402 411 HTTPS support
403 412 -------------
404 413
405 414 Kallithea will by default generate URLs based on the WSGI environment.
406 415
407 416 Alternatively, you can use some special configuration settings to control
408 417 directly which scheme/protocol Kallithea will use when generating URLs:
409 418
410 419 - With ``https_fixup = true``, the scheme will be taken from the
411 420 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
412 421 (default ``http``).
413 422 - With ``force_https = true`` the default will be ``https``.
414 423 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
415 424
416 425 .. _nginx_virtual_host:
417 426
418 427
419 428 Nginx virtual host example
420 429 --------------------------
421 430
422 431 Sample config for Nginx using proxy:
423 432
424 433 .. code-block:: nginx
425 434
426 435 upstream kallithea {
427 436 server 127.0.0.1:5000;
428 437 # add more instances for load balancing
429 438 #server 127.0.0.1:5001;
430 439 #server 127.0.0.1:5002;
431 440 }
432 441
433 442 ## gist alias
434 443 server {
435 444 listen 443;
436 445 server_name gist.example.com;
437 446 access_log /var/log/nginx/gist.access.log;
438 447 error_log /var/log/nginx/gist.error.log;
439 448
440 449 ssl on;
441 450 ssl_certificate gist.your.kallithea.server.crt;
442 451 ssl_certificate_key gist.your.kallithea.server.key;
443 452
444 453 ssl_session_timeout 5m;
445 454
446 455 ssl_protocols SSLv3 TLSv1;
447 456 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
448 457 ssl_prefer_server_ciphers on;
449 458
450 459 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
451 460 rewrite (.*) https://kallithea.example.com/_admin/gists;
452 461 }
453 462
454 463 server {
455 464 listen 443;
456 465 server_name kallithea.example.com
457 466 access_log /var/log/nginx/kallithea.access.log;
458 467 error_log /var/log/nginx/kallithea.error.log;
459 468
460 469 ssl on;
461 470 ssl_certificate your.kallithea.server.crt;
462 471 ssl_certificate_key your.kallithea.server.key;
463 472
464 473 ssl_session_timeout 5m;
465 474
466 475 ssl_protocols SSLv3 TLSv1;
467 476 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
468 477 ssl_prefer_server_ciphers on;
469 478
470 479 ## uncomment root directive if you want to serve static files by nginx
471 480 ## requires static_files = false in .ini file
472 481 #root /srv/kallithea/kallithea/kallithea/public;
473 482 include /etc/nginx/proxy.conf;
474 483 location / {
475 484 try_files $uri @kallithea;
476 485 }
477 486
478 487 location @kallithea {
479 488 proxy_pass http://127.0.0.1:5000;
480 489 }
481 490
482 491 }
483 492
484 493 Here's the proxy.conf. It's tuned so it will not timeout on long
485 494 pushes or large pushes::
486 495
487 496 proxy_redirect off;
488 497 proxy_set_header Host $host;
489 498 ## needed for container auth
490 499 #proxy_set_header REMOTE_USER $remote_user;
491 500 #proxy_set_header X-Forwarded-User $remote_user;
492 501 proxy_set_header X-Url-Scheme $scheme;
493 502 proxy_set_header X-Host $http_host;
494 503 proxy_set_header X-Real-IP $remote_addr;
495 504 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
496 505 proxy_set_header Proxy-host $proxy_host;
497 506 proxy_buffering off;
498 507 proxy_connect_timeout 7200;
499 508 proxy_send_timeout 7200;
500 509 proxy_read_timeout 7200;
501 510 proxy_buffers 8 32k;
502 511 client_max_body_size 1024m;
503 512 client_body_buffer_size 128k;
504 513 large_client_header_buffers 8 64k;
505 514
506 515 .. _apache_virtual_host_reverse_proxy:
507 516
508 517
509 518 Apache virtual host reverse proxy example
510 519 -----------------------------------------
511 520
512 521 Here is a sample configuration file for Apache using proxy:
513 522
514 523 .. code-block:: apache
515 524
516 525 <VirtualHost *:80>
517 526 ServerName kallithea.example.com
518 527
519 528 <Proxy *>
520 529 # For Apache 2.4 and later:
521 530 Require all granted
522 531
523 532 # For Apache 2.2 and earlier, instead use:
524 533 # Order allow,deny
525 534 # Allow from all
526 535 </Proxy>
527 536
528 537 #important !
529 538 #Directive to properly generate url (clone url) for Kallithea
530 539 ProxyPreserveHost On
531 540
532 541 #kallithea instance
533 542 ProxyPass / http://127.0.0.1:5000/
534 543 ProxyPassReverse / http://127.0.0.1:5000/
535 544
536 545 #to enable https use line below
537 546 #SetEnvIf X-Url-Scheme https HTTPS=1
538 547 </VirtualHost>
539 548
540 549 Additional tutorial
541 550 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
542 551
543 552 .. _apache_subdirectory:
544 553
545 554
546 555 Apache as subdirectory
547 556 ----------------------
548 557
549 558 Apache subdirectory part:
550 559
551 560 .. code-block:: apache
552 561
553 562 <Location /PREFIX >
554 563 ProxyPass http://127.0.0.1:5000/PREFIX
555 564 ProxyPassReverse http://127.0.0.1:5000/PREFIX
556 565 SetEnvIf X-Url-Scheme https HTTPS=1
557 566 </Location>
558 567
559 568 Besides the regular apache setup you will need to add the following line
560 569 into ``[app:main]`` section of your .ini file::
561 570
562 571 filter-with = proxy-prefix
563 572
564 573 Add the following at the end of the .ini file::
565 574
566 575 [filter:proxy-prefix]
567 576 use = egg:PasteDeploy#prefix
568 577 prefix = /PREFIX
569 578
570 579 then change ``PREFIX`` into your chosen prefix
571 580
572 581 .. _apache_mod_wsgi:
573 582
574 583
575 584 Apache with mod_wsgi
576 585 --------------------
577 586
578 587 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
579 588 that, you'll need to:
580 589
581 590 - Install mod_wsgi. If using a Debian-based distro, you can install
582 591 the package libapache2-mod-wsgi::
583 592
584 593 aptitude install libapache2-mod-wsgi
585 594
586 595 - Enable mod_wsgi::
587 596
588 597 a2enmod wsgi
589 598
590 599 - Add global Apache configuration to tell mod_wsgi that Python only will be
591 600 used in the WSGI processes and shouldn't be initialized in the Apache
592 601 processes::
593 602
594 603 WSGIRestrictEmbedded On
595 604
596 605 - Create a WSGI dispatch script, like the one below. Make sure you
597 606 check that the paths correctly point to where you installed Kallithea
598 607 and its Python Virtual Environment.
599 608
600 609 .. code-block:: python
601 610
602 611 import os
603 612 os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
604 613
605 614 # sometimes it's needed to set the current dir
606 615 os.chdir('/srv/kallithea/')
607 616
608 617 import site
609 618 site.addsitedir("/srv/kallithea/venv/lib/python3.7/site-packages")
610 619
611 620 ini = '/srv/kallithea/my.ini'
612 621 from logging.config import fileConfig
613 622 fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
614 623 from paste.deploy import loadapp
615 624 application = loadapp('config:' + ini)
616 625
617 626 Or using proper virtualenv activation:
618 627
619 628 .. code-block:: python
620 629
621 630 activate_this = '/srv/kallithea/venv/bin/activate_this.py'
622 631 execfile(activate_this, dict(__file__=activate_this))
623 632
624 633 import os
625 634 os.environ['HOME'] = '/srv/kallithea'
626 635
627 636 ini = '/srv/kallithea/kallithea.ini'
628 637 from logging.config import fileConfig
629 638 fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
630 639 from paste.deploy import loadapp
631 640 application = loadapp('config:' + ini)
632 641
633 642 - Add the necessary ``WSGI*`` directives to the Apache Virtual Host configuration
634 643 file, like in the example below. Notice that the WSGI dispatch script created
635 644 above is referred to with the ``WSGIScriptAlias`` directive.
636 645 The default locale settings Apache provides for web services are often not
637 646 adequate, with `C` as the default language and `ASCII` as the encoding.
638 647 Instead, use the ``lang`` parameter of ``WSGIDaemonProcess`` to specify a
639 648 suitable locale. See also the :ref:`overview` section and the
640 649 `WSGIDaemonProcess documentation`_.
641 650
642 651 Apache will by default run as a special Apache user, on Linux systems
643 652 usually ``www-data`` or ``apache``. If you need to have the repositories
644 653 directory owned by a different user, use the user and group options to
645 654 WSGIDaemonProcess to set the name of the user and group.
646 655
647 656 Once again, check that all paths are correctly specified.
648 657
649 658 .. code-block:: apache
650 659
651 660 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
652 661 python-home=/srv/kallithea/venv lang=C.UTF-8
653 662 WSGIProcessGroup kallithea
654 663 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
655 664 WSGIPassAuthorization On
656 665
657 666 Or if using a dispatcher WSGI script with proper virtualenv activation:
658 667
659 668 .. code-block:: apache
660 669
661 670 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 lang=en_US.utf8
662 671 WSGIProcessGroup kallithea
663 672 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
664 673 WSGIPassAuthorization On
665 674
666 675
667 676 Other configuration files
668 677 -------------------------
669 678
670 679 A number of `example init.d scripts`__ can be found in
671 680 the ``init.d`` directory of the Kallithea source.
672 681
673 682 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
674 683
675 684
676 685 .. _python: http://www.python.org/
677 686 .. _Python regular expression documentation: https://docs.python.org/2/library/re.html
678 687 .. _Mercurial: https://www.mercurial-scm.org/
679 688 .. _Celery: http://celeryproject.org/
680 689 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
681 690 .. _RabbitMQ: http://www.rabbitmq.com/
682 691 .. _Redis: http://redis.io/
683 692 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
684 693 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
685 694 .. _WSGIDaemonProcess documentation: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html
@@ -1,80 +1,82 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 import click
15 15
16 16 import kallithea
17 17 import kallithea.bin.kallithea_cli_base as cli_base
18 18 from kallithea.lib.db_manage import DbManage
19 19 from kallithea.model.meta import Session
20 20
21 21
22 22 @cli_base.register_command(config_file=True)
23 @click.option('--reuse/--no-reuse', default=False,
24 help='Reuse and clean existing database instead of dropping and creating (default: no reuse)')
23 25 @click.option('--user', help='Username of administrator account.')
24 26 @click.option('--password', help='Password for administrator account.')
25 27 @click.option('--email', help='Email address of administrator account.')
26 28 @click.option('--repos', help='Absolute path to repositories location.')
27 29 @click.option('--force-yes', is_flag=True, help='Answer yes to every question.')
28 30 @click.option('--force-no', is_flag=True, help='Answer no to every question.')
29 31 @click.option('--public-access/--no-public-access', default=True,
30 32 help='Enable/disable public access on this installation (default: enable)')
31 def db_create(user, password, email, repos, force_yes, force_no, public_access):
33 def db_create(user, password, email, repos, force_yes, force_no, public_access, reuse):
32 34 """Initialize the database.
33 35
34 36 Create all required tables in the database specified in the configuration
35 37 file. Create the administrator account. Set certain settings based on
36 38 values you provide.
37 39
38 40 You can pass the answers to all questions as options to this command.
39 41 """
40 42 dbconf = kallithea.CONFIG['sqlalchemy.url']
41 43
42 44 # force_ask should be True (yes), False (no), or None (ask)
43 45 if force_yes:
44 46 force_ask = True
45 47 elif force_no:
46 48 force_ask = False
47 49 else:
48 50 force_ask = None
49 51
50 52 cli_args = dict(
51 53 username=user,
52 54 password=password,
53 55 email=email,
54 56 repos_location=repos,
55 57 force_ask=force_ask,
56 58 public_access=public_access,
57 59 )
58 60 dbmanage = DbManage(dbconf=dbconf, root=kallithea.CONFIG['here'],
59 61 tests=False, cli_args=cli_args)
60 dbmanage.create_tables()
62 dbmanage.create_tables(reuse_database=reuse)
61 63 repo_root_path = dbmanage.prompt_repo_root_path(None)
62 64 dbmanage.create_settings(repo_root_path)
63 65 dbmanage.create_default_user()
64 66 dbmanage.admin_prompt()
65 67 dbmanage.create_permissions()
66 68 dbmanage.populate_default_permissions()
67 69 Session().commit()
68 70
69 71 # initial repository scan
70 72 kallithea.config.application.make_app(
71 73 kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf)
72 74 added, _ = kallithea.lib.utils.repo2db_mapper(kallithea.model.scm.ScmModel().repo_scan())
73 75 if added:
74 76 click.echo('Initial repository scan: added following repositories:')
75 77 click.echo('\t%s' % '\n\t'.join(added))
76 78 else:
77 79 click.echo('Initial repository scan: no repositories found.')
78 80
79 81 click.echo('Database set up successfully.')
80 82 click.echo("Don't forget to build the front-end using 'kallithea-cli front-end-build'.")
@@ -1,336 +1,344 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.lib.db_manage
16 16 ~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Database creation, and setup module for Kallithea. Used for creation
19 19 of database as well as for migration operations
20 20
21 21 This file was forked by the Kallithea project in July 2014.
22 22 Original author and date, and relevant copyright and licensing information is below:
23 23 :created_on: Apr 10, 2010
24 24 :author: marcink
25 25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 26 :license: GPLv3, see LICENSE.md for more details.
27 27 """
28 28
29 29 import logging
30 30 import os
31 31 import sys
32 32 import uuid
33 33
34 34 import alembic.command
35 35 import alembic.config
36 36 import sqlalchemy
37 37 from sqlalchemy.engine import create_engine
38 38
39 39 from kallithea.model.base import init_model
40 40 from kallithea.model.db import Repository, Setting, Ui, User
41 41 from kallithea.model.meta import Base, Session
42 42 from kallithea.model.permission import PermissionModel
43 43 from kallithea.model.user import UserModel
44 44
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class DbManage(object):
50 50 def __init__(self, dbconf, root, tests=False, SESSION=None, cli_args=None):
51 51 self.dbname = dbconf.split('/')[-1]
52 52 self.tests = tests
53 53 self.root = root
54 54 self.dburi = dbconf
55 55 self.cli_args = cli_args or {}
56 56 self.init_db(SESSION=SESSION)
57 57
58 58 def _ask_ok(self, msg):
59 59 """Invoke ask_ok unless the force_ask option provides the answer"""
60 60 force_ask = self.cli_args.get('force_ask')
61 61 if force_ask is not None:
62 62 return force_ask
63 63 from kallithea.lib.utils2 import ask_ok
64 64 return ask_ok(msg)
65 65
66 66 def init_db(self, SESSION=None):
67 67 if SESSION:
68 68 self.sa = SESSION
69 69 else:
70 70 # init new sessions
71 71 engine = create_engine(self.dburi)
72 72 init_model(engine)
73 73 self.sa = Session()
74 74
75 def create_tables(self):
75 def create_tables(self, reuse_database=False):
76 76 """
77 77 Create database (optional) and tables.
78 The database will be dropped (if it exists) and a new one created.
78 If reuse_database is false, the database will be dropped (if it exists)
79 and a new one created. If true, the existing database will be reused
80 and cleaned for content.
79 81 """
80 82 url = sqlalchemy.engine.url.make_url(self.dburi)
81 83 database = url.database
82 log.info("The existing database %r will be destroyed and created." % database)
84 if reuse_database:
85 log.info("The content of the database %r will be destroyed and new tables created." % database)
86 else:
87 log.info("The existing database %r will be destroyed and a new one created." % database)
88
83 89 if not self.tests:
84 90 if not self._ask_ok('Are you sure to destroy old database? [y/n]'):
85 91 print('Nothing done.')
86 92 sys.exit(0)
87 93
88 if True:
94 if reuse_database:
95 Base.metadata.drop_all()
96 else:
89 97 if url.drivername == 'mysql':
90 98 url.database = None # don't connect to the database (it might not exist)
91 99 engine = sqlalchemy.create_engine(url)
92 100 with engine.connect() as conn:
93 101 conn.execute('DROP DATABASE IF EXISTS `%s`' % database)
94 102 conn.execute('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci' % database)
95 103 elif url.drivername == 'postgresql':
96 104 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
97 105 url.database = 'postgres' # connect to the system database (as the real one might not exist)
98 106 engine = sqlalchemy.create_engine(url)
99 107 with engine.connect() as conn:
100 108 conn.connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
101 109 conn.execute('DROP DATABASE IF EXISTS "%s"' % database)
102 110 conn.execute('CREATE DATABASE "%s"' % database)
103 111 else:
104 112 # Some databases enforce foreign key constraints and Base.metadata.drop_all() doesn't work, but this is
105 113 # known to work on SQLite - possibly not on other databases with strong referential integrity
106 114 Base.metadata.drop_all()
107 115
108 116 Base.metadata.create_all(checkfirst=False)
109 117
110 118 # Create an Alembic configuration and generate the version table,
111 119 # "stamping" it with the most recent Alembic migration revision, to
112 120 # tell Alembic that all the schema upgrades are already in effect.
113 121 alembic_cfg = alembic.config.Config()
114 122 alembic_cfg.set_main_option('script_location', 'kallithea:alembic')
115 123 alembic_cfg.set_main_option('sqlalchemy.url', self.dburi)
116 124 # This command will give an error in an Alembic multi-head scenario,
117 125 # but in practice, such a scenario should not come up during database
118 126 # creation, even during development.
119 127 alembic.command.stamp(alembic_cfg, 'head')
120 128
121 129 log.info('Created tables for %s', self.dbname)
122 130
123 131 def admin_prompt(self, second=False):
124 132 if not self.tests:
125 133 import getpass
126 134
127 135 username = self.cli_args.get('username')
128 136 password = self.cli_args.get('password')
129 137 email = self.cli_args.get('email')
130 138
131 139 def get_password():
132 140 password = getpass.getpass('Specify admin password '
133 141 '(min 6 chars):')
134 142 confirm = getpass.getpass('Confirm password:')
135 143
136 144 if password != confirm:
137 145 log.error('passwords mismatch')
138 146 return False
139 147 if len(password) < 6:
140 148 log.error('password is to short use at least 6 characters')
141 149 return False
142 150
143 151 return password
144 152 if username is None:
145 153 username = input('Specify admin username:')
146 154 if password is None:
147 155 password = get_password()
148 156 if not password:
149 157 # second try
150 158 password = get_password()
151 159 if not password:
152 160 sys.exit()
153 161 if email is None:
154 162 email = input('Specify admin email:')
155 163 self.create_user(username, password, email, True)
156 164 else:
157 165 log.info('creating admin and regular test users')
158 166 from kallithea.tests.base import TEST_USER_ADMIN_LOGIN, \
159 167 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
160 168 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
161 169 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
162 170 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
163 171
164 172 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
165 173 TEST_USER_ADMIN_EMAIL, True)
166 174
167 175 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
168 176 TEST_USER_REGULAR_EMAIL, False)
169 177
170 178 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
171 179 TEST_USER_REGULAR2_EMAIL, False)
172 180
173 181 def create_auth_plugin_options(self, skip_existing=False):
174 182 """
175 183 Create default auth plugin settings, and make it active
176 184
177 185 :param skip_existing:
178 186 """
179 187
180 188 for k, v, t in [('auth_plugins', 'kallithea.lib.auth_modules.auth_internal', 'list'),
181 189 ('auth_internal_enabled', 'True', 'bool')]:
182 190 if skip_existing and Setting.get_by_name(k) is not None:
183 191 log.debug('Skipping option %s', k)
184 192 continue
185 193 setting = Setting(k, v, t)
186 194 self.sa.add(setting)
187 195
188 196 def create_default_options(self, skip_existing=False):
189 197 """Creates default settings"""
190 198
191 199 for k, v, t in [
192 200 ('default_repo_enable_downloads', False, 'bool'),
193 201 ('default_repo_enable_statistics', False, 'bool'),
194 202 ('default_repo_private', False, 'bool'),
195 203 ('default_repo_type', 'hg', 'unicode')
196 204 ]:
197 205 if skip_existing and Setting.get_by_name(k) is not None:
198 206 log.debug('Skipping option %s', k)
199 207 continue
200 208 setting = Setting(k, v, t)
201 209 self.sa.add(setting)
202 210
203 211 def prompt_repo_root_path(self, test_repo_path='', retries=3):
204 212 _path = self.cli_args.get('repos_location')
205 213 if retries == 3:
206 214 log.info('Setting up repositories config')
207 215
208 216 if _path is not None:
209 217 path = _path
210 218 elif not self.tests and not test_repo_path:
211 219 path = input(
212 220 'Enter a valid absolute path to store repositories. '
213 221 'All repositories in that path will be added automatically:'
214 222 )
215 223 else:
216 224 path = test_repo_path
217 225 path_ok = True
218 226
219 227 # check proper dir
220 228 if not os.path.isdir(path):
221 229 path_ok = False
222 230 log.error('Given path %s is not a valid directory', path)
223 231
224 232 elif not os.path.isabs(path):
225 233 path_ok = False
226 234 log.error('Given path %s is not an absolute path', path)
227 235
228 236 # check if path is at least readable.
229 237 if not os.access(path, os.R_OK):
230 238 path_ok = False
231 239 log.error('Given path %s is not readable', path)
232 240
233 241 # check write access, warn user about non writeable paths
234 242 elif not os.access(path, os.W_OK) and path_ok:
235 243 log.warning('No write permission to given path %s', path)
236 244 if not self._ask_ok('Given path %s is not writeable, do you want to '
237 245 'continue with read only mode ? [y/n]' % (path,)):
238 246 log.error('Canceled by user')
239 247 sys.exit(-1)
240 248
241 249 if retries == 0:
242 250 sys.exit('max retries reached')
243 251 if not path_ok:
244 252 if _path is not None:
245 253 sys.exit('Invalid repo path: %s' % _path)
246 254 retries -= 1
247 255 return self.prompt_repo_root_path(test_repo_path, retries) # recursing!!!
248 256
249 257 real_path = os.path.normpath(os.path.realpath(path))
250 258
251 259 if real_path != os.path.normpath(path):
252 260 log.warning('Using normalized path %s instead of %s', real_path, path)
253 261
254 262 return real_path
255 263
256 264 def create_settings(self, repo_root_path):
257 265 ui_config = [
258 266 ('paths', '/', repo_root_path, True),
259 267 #('phases', 'publish', 'false', False)
260 268 ('hooks', Ui.HOOK_UPDATE, 'hg update >&2', False),
261 269 ('hooks', Ui.HOOK_REPO_SIZE, 'python:kallithea.lib.hooks.repo_size', True),
262 270 ('extensions', 'largefiles', '', True),
263 271 ('largefiles', 'usercache', os.path.join(repo_root_path, '.cache', 'largefiles'), True),
264 272 ('extensions', 'hgsubversion', '', False),
265 273 ('extensions', 'hggit', '', False),
266 274 ]
267 275 for ui_section, ui_key, ui_value, ui_active in ui_config:
268 276 ui_conf = Ui(
269 277 ui_section=ui_section,
270 278 ui_key=ui_key,
271 279 ui_value=ui_value,
272 280 ui_active=ui_active)
273 281 self.sa.add(ui_conf)
274 282
275 283 settings = [
276 284 ('realm', 'Kallithea', 'unicode'),
277 285 ('title', '', 'unicode'),
278 286 ('ga_code', '', 'unicode'),
279 287 ('show_public_icon', True, 'bool'),
280 288 ('show_private_icon', True, 'bool'),
281 289 ('stylify_metalabels', False, 'bool'),
282 290 ('dashboard_items', 100, 'int'), # TODO: call it page_size
283 291 ('admin_grid_items', 25, 'int'),
284 292 ('show_version', True, 'bool'),
285 293 ('use_gravatar', True, 'bool'),
286 294 ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
287 295 ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
288 296 ('clone_ssh_tmpl', Repository.DEFAULT_CLONE_SSH, 'unicode'),
289 297 ]
290 298 for key, val, type_ in settings:
291 299 sett = Setting(key, val, type_)
292 300 self.sa.add(sett)
293 301
294 302 self.create_auth_plugin_options()
295 303 self.create_default_options()
296 304
297 305 log.info('Populated Ui and Settings defaults')
298 306
299 307 def create_user(self, username, password, email='', admin=False):
300 308 log.info('creating user %s', username)
301 309 UserModel().create_or_update(username, password, email,
302 310 firstname='Kallithea', lastname='Admin',
303 311 active=True, admin=admin,
304 312 extern_type=User.DEFAULT_AUTH_TYPE)
305 313
306 314 def create_default_user(self):
307 315 log.info('creating default user')
308 316 # create default user for handling default permissions.
309 317 user = UserModel().create_or_update(username=User.DEFAULT_USER_NAME,
310 318 password=str(uuid.uuid1())[:20],
311 319 email='anonymous@kallithea-scm.org',
312 320 firstname='Anonymous',
313 321 lastname='User')
314 322 # based on configuration options activate/deactivate this user which
315 323 # controls anonymous access
316 324 if self.cli_args.get('public_access') is False:
317 325 log.info('Public access disabled')
318 326 user.active = False
319 327 Session().commit()
320 328
321 329 def create_permissions(self):
322 330 """
323 331 Creates all permissions defined in the system
324 332 """
325 333 # module.(access|create|change|delete)_[name]
326 334 # module.(none|read|write|admin)
327 335 log.info('creating permissions')
328 336 PermissionModel().create_permissions()
329 337
330 338 def populate_default_permissions(self):
331 339 """
332 340 Populate default permissions. It will create only the default
333 341 permissions that are missing, and not alter already defined ones
334 342 """
335 343 log.info('creating default user permissions')
336 344 PermissionModel().create_default_permissions(user=User.DEFAULT_USER_NAME)
General Comments 0
You need to be logged in to leave comments. Login now