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