Commit | Line | Data |
---|---|---|
105369a4 DT |
1 | ;;; GNU Guix --- Functional package management for GNU |
2 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> | |
9b1cee97 | 3 | ;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org> |
8823ed4e | 4 | ;;; Copyright © 2016 Leo Famulari <leo@famulari.name> |
105369a4 DT |
5 | ;;; |
6 | ;;; This file is part of GNU Guix. | |
7 | ;;; | |
8 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | |
9 | ;;; under the terms of the GNU General Public License as published by | |
10 | ;;; the Free Software Foundation; either version 3 of the License, or (at | |
11 | ;;; your option) any later version. | |
12 | ;;; | |
13 | ;;; GNU Guix is distributed in the hope that it will be useful, but | |
14 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | ;;; GNU General Public License for more details. | |
17 | ;;; | |
18 | ;;; You should have received a copy of the GNU General Public License | |
19 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | |
20 | ||
21 | (define-module (gnu services databases) | |
22 | #:use-module (gnu services) | |
0190c1c0 | 23 | #:use-module (gnu services shepherd) |
105369a4 DT |
24 | #:use-module (gnu system shadow) |
25 | #:use-module (gnu packages admin) | |
26 | #:use-module (gnu packages databases) | |
27 | #:use-module (guix records) | |
105369a4 | 28 | #:use-module (guix gexp) |
0adfe95a | 29 | #:use-module (ice-9 match) |
24e96431 TČ |
30 | #:export (postgresql-configuration |
31 | postgresql-configuration? | |
32 | postgresql-service | |
33 | postgresql-service-type | |
34 | ||
6575183b | 35 | mysql-service |
24e96431 TČ |
36 | mysql-service-type |
37 | mysql-configuration | |
38 | mysql-configuration?)) | |
105369a4 DT |
39 | |
40 | ;;; Commentary: | |
41 | ;;; | |
42 | ;;; Database services. | |
43 | ;;; | |
44 | ;;; Code: | |
45 | ||
0adfe95a LC |
46 | (define-record-type* <postgresql-configuration> |
47 | postgresql-configuration make-postgresql-configuration | |
48 | postgresql-configuration? | |
49 | (postgresql postgresql-configuration-postgresql ;<package> | |
50 | (default postgresql)) | |
51 | (config-file postgresql-configuration-file) | |
52 | (data-directory postgresql-configuration-data-directory)) | |
53 | ||
105369a4 | 54 | (define %default-postgres-hba |
be1c2c54 LC |
55 | (plain-file "pg_hba.conf" |
56 | " | |
105369a4 DT |
57 | local all all trust |
58 | host all all 127.0.0.1/32 trust | |
59 | host all all ::1/128 trust")) | |
60 | ||
61 | (define %default-postgres-ident | |
be1c2c54 | 62 | (plain-file "pg_ident.conf" |
105369a4 DT |
63 | "# MAPNAME SYSTEM-USERNAME PG-USERNAME")) |
64 | ||
65 | (define %default-postgres-config | |
be1c2c54 | 66 | (mixed-text-file "postgresql.conf" |
9b1cee97 | 67 | "log_destination = 'syslog'\n" |
be1c2c54 | 68 | "hba_file = '" %default-postgres-hba "'\n" |
8823ed4e | 69 | "ident_file = '" %default-postgres-ident "'\n")) |
105369a4 | 70 | |
0adfe95a LC |
71 | (define %postgresql-accounts |
72 | (list (user-group (name "postgres") (system? #t)) | |
73 | (user-account | |
74 | (name "postgres") | |
75 | (group "postgres") | |
76 | (system? #t) | |
77 | (comment "PostgreSQL server user") | |
78 | (home-directory "/var/empty") | |
79 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | |
80 | ||
81 | (define postgresql-activation | |
82 | (match-lambda | |
83 | (($ <postgresql-configuration> postgresql config-file data-directory) | |
84 | #~(begin | |
85 | (use-modules (guix build utils) | |
86 | (ice-9 match)) | |
87 | ||
88 | (let ((user (getpwnam "postgres")) | |
89 | (initdb (string-append #$postgresql "/bin/initdb"))) | |
90 | ;; Create db state directory. | |
91 | (mkdir-p #$data-directory) | |
92 | (chown #$data-directory (passwd:uid user) (passwd:gid user)) | |
93 | ||
94 | ;; Drop privileges and init state directory in a new | |
95 | ;; process. Wait for it to finish before proceeding. | |
96 | (match (primitive-fork) | |
97 | (0 | |
98 | ;; Exit with a non-zero status code if an exception is thrown. | |
99 | (dynamic-wind | |
100 | (const #t) | |
101 | (lambda () | |
102 | (setgid (passwd:gid user)) | |
103 | (setuid (passwd:uid user)) | |
104 | (primitive-exit (system* initdb "-D" #$data-directory))) | |
105 | (lambda () | |
106 | (primitive-exit 1)))) | |
107 | (pid (waitpid pid)))))))) | |
108 | ||
d4053c71 | 109 | (define postgresql-shepherd-service |
0adfe95a LC |
110 | (match-lambda |
111 | (($ <postgresql-configuration> postgresql config-file data-directory) | |
112 | (let ((start-script | |
113 | ;; Wrapper script that switches to the 'postgres' user before | |
114 | ;; launching daemon. | |
115 | (program-file "start-postgres" | |
116 | #~(let ((user (getpwnam "postgres")) | |
117 | (postgres (string-append #$postgresql | |
118 | "/bin/postgres"))) | |
119 | (setgid (passwd:gid user)) | |
120 | (setuid (passwd:uid user)) | |
121 | (system* postgres | |
122 | (string-append "--config-file=" | |
123 | #$config-file) | |
124 | "-D" #$data-directory))))) | |
d4053c71 | 125 | (list (shepherd-service |
0adfe95a LC |
126 | (provision '(postgres)) |
127 | (documentation "Run the PostgreSQL daemon.") | |
9b1cee97 | 128 | (requirement '(user-processes loopback syslogd)) |
0adfe95a LC |
129 | (start #~(make-forkexec-constructor #$start-script)) |
130 | (stop #~(make-kill-destructor)))))))) | |
131 | ||
132 | (define postgresql-service-type | |
133 | (service-type (name 'postgresql) | |
134 | (extensions | |
d4053c71 AK |
135 | (list (service-extension shepherd-root-service-type |
136 | postgresql-shepherd-service) | |
0adfe95a LC |
137 | (service-extension activation-service-type |
138 | postgresql-activation) | |
139 | (service-extension account-service-type | |
140 | (const %postgresql-accounts)))))) | |
141 | ||
105369a4 DT |
142 | (define* (postgresql-service #:key (postgresql postgresql) |
143 | (config-file %default-postgres-config) | |
144 | (data-directory "/var/lib/postgresql/data")) | |
145 | "Return a service that runs @var{postgresql}, the PostgreSQL database server. | |
146 | ||
147 | The PostgreSQL daemon loads its runtime configuration from @var{config-file} | |
148 | and stores the database cluster in @var{data-directory}." | |
0adfe95a LC |
149 | (service postgresql-service-type |
150 | (postgresql-configuration | |
151 | (postgresql postgresql) | |
152 | (config-file config-file) | |
153 | (data-directory data-directory)))) | |
6575183b SB |
154 | |
155 | \f | |
156 | ;;; | |
157 | ;;; MySQL. | |
158 | ;;; | |
159 | ||
160 | (define-record-type* <mysql-configuration> | |
161 | mysql-configuration make-mysql-configuration | |
162 | mysql-configuration? | |
163 | (mysql mysql-configuration-mysql (default mariadb))) | |
164 | ||
165 | (define %mysql-accounts | |
166 | (list (user-group | |
167 | (name "mysql") | |
168 | (system? #t)) | |
169 | (user-account | |
170 | (name "mysql") | |
171 | (group "mysql") | |
172 | (system? #t) | |
173 | (home-directory "/var/empty") | |
174 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | |
175 | ||
176 | (define mysql-configuration-file | |
177 | (match-lambda | |
178 | (($ <mysql-configuration> mysql) | |
179 | (plain-file "my.cnf" "[mysqld] | |
180 | datadir=/var/lib/mysql | |
181 | socket=/run/mysqld/mysqld.sock | |
182 | ")))) | |
183 | ||
184 | (define (%mysql-activation config) | |
185 | "Return an activation gexp for the MySQL or MariaDB database server." | |
186 | (let ((mysql (mysql-configuration-mysql config)) | |
187 | (my.cnf (mysql-configuration-file config))) | |
188 | #~(begin | |
189 | (use-modules (ice-9 popen) | |
190 | (guix build utils)) | |
191 | (let* ((mysqld (string-append #$mysql "/bin/mysqld")) | |
192 | (user (getpwnam "mysql")) | |
193 | (uid (passwd:uid user)) | |
194 | (gid (passwd:gid user)) | |
195 | (datadir "/var/lib/mysql") | |
196 | (rundir "/run/mysqld")) | |
197 | (mkdir-p datadir) | |
198 | (chown datadir uid gid) | |
199 | (mkdir-p rundir) | |
200 | (chown rundir uid gid) | |
201 | ;; Initialize the database when it doesn't exist. | |
202 | (when (not (file-exists? (string-append datadir "/mysql"))) | |
203 | (if (string-prefix? "mysql-" (strip-store-file-name #$mysql)) | |
204 | ;; For MySQL. | |
205 | (system* mysqld | |
206 | (string-append "--defaults-file=" #$my.cnf) | |
207 | "--initialize" | |
208 | "--user=mysql") | |
209 | ;; For MariaDB. | |
210 | ;; XXX: The 'mysql_install_db' script doesn't work directly | |
211 | ;; due to missing 'mkdir' in PATH. | |
212 | (let ((p (open-pipe* OPEN_WRITE mysqld | |
213 | (string-append | |
214 | "--defaults-file=" #$my.cnf) | |
215 | "--bootstrap" | |
216 | "--user=mysql"))) | |
217 | ;; Create the system database, as does by 'mysql_install_db'. | |
218 | (display "create database mysql;\n" p) | |
219 | (display "use mysql;\n" p) | |
220 | (for-each | |
221 | (lambda (sql) | |
222 | (call-with-input-file | |
223 | (string-append #$mysql "/share/mysql/" sql) | |
224 | (lambda (in) (dump-port in p)))) | |
225 | '("mysql_system_tables.sql" | |
226 | "mysql_performance_tables.sql" | |
227 | "mysql_system_tables_data.sql" | |
228 | "fill_help_tables.sql")) | |
229 | ;; Remove the anonymous user and disable root access from | |
230 | ;; remote machines, as does by 'mysql_secure_installation'. | |
231 | (display " | |
232 | DELETE FROM user WHERE User=''; | |
233 | DELETE FROM user WHERE User='root' AND | |
234 | Host NOT IN ('localhost', '127.0.0.1', '::1'); | |
235 | FLUSH PRIVILEGES; | |
236 | " p) | |
237 | (close-pipe p)))))))) | |
238 | ||
239 | (define (mysql-shepherd-service config) | |
240 | (list (shepherd-service | |
241 | (provision '(mysql)) | |
242 | (documentation "Run the MySQL server.") | |
243 | (start (let ((mysql (mysql-configuration-mysql config)) | |
244 | (my.cnf (mysql-configuration-file config))) | |
245 | #~(make-forkexec-constructor | |
246 | (list (string-append #$mysql "/bin/mysqld") | |
247 | (string-append "--defaults-file=" #$my.cnf)) | |
248 | #:user "mysql" #:group "mysql"))) | |
249 | (stop #~(make-kill-destructor))))) | |
250 | ||
251 | (define mysql-service-type | |
252 | (service-type | |
253 | (name 'mysql) | |
254 | (extensions | |
255 | (list (service-extension account-service-type | |
256 | (const %mysql-accounts)) | |
257 | (service-extension activation-service-type | |
258 | %mysql-activation) | |
259 | (service-extension shepherd-root-service-type | |
260 | mysql-shepherd-service))))) | |
261 | ||
262 | (define* (mysql-service #:key (config (mysql-configuration))) | |
263 | "Return a service that runs @command{mysqld}, the MySQL or MariaDB | |
264 | database server. | |
265 | ||
266 | The optional @var{config} argument specifies the configuration for | |
267 | @command{mysqld}, which should be a @code{<mysql-configuration>} object." | |
268 | (service mysql-service-type config)) |