1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
3 ;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
4 ;;; Copyright © 2016 Leo Famulari <leo@famulari.name>
5 ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
6 ;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
8 ;;; This file is part of GNU Guix.
10 ;;; GNU Guix is free software; you can redistribute it and/or modify it
11 ;;; under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or (at
13 ;;; your option) any later version.
15 ;;; GNU Guix is distributed in the hope that it will be useful, but
16 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
23 (define-module (gnu services databases)
24 #:use-module (gnu services)
25 #:use-module (gnu services shepherd)
26 #:use-module (gnu system shadow)
27 #:use-module (gnu packages admin)
28 #:use-module (gnu packages databases)
29 #:use-module (guix modules)
30 #:use-module (guix records)
31 #:use-module (guix gexp)
32 #:use-module (ice-9 match)
33 #:export (postgresql-configuration
34 postgresql-configuration?
36 postgresql-service-type
38 memcached-service-type
39 <memcached-configuration>
40 memcached-configuration
41 memcached-configuration?
42 memcached-configuration-memecached
43 memcached-configuration-interfaces
44 memcached-configuration-tcp-port
45 memcached-configuration-udp-port
46 memcached-configuration-additional-options
48 <mongodb-configuration>
50 mongodb-configuration?
51 mongodb-configuration-mongodb
52 mongodb-configuration-config-file
53 mongodb-configuration-data-directory
67 ;;; Database services.
71 (define-record-type* <postgresql-configuration>
72 postgresql-configuration make-postgresql-configuration
73 postgresql-configuration?
74 (postgresql postgresql-configuration-postgresql ;<package>
76 (port postgresql-configuration-port
78 (locale postgresql-configuration-locale
79 (default "en_US.utf8"))
80 (config-file postgresql-configuration-file
81 (default %default-postgres-config))
82 (data-directory postgresql-configuration-data-directory
83 (default "/var/lib/postgresql/data")))
85 (define %default-postgres-hba
86 (plain-file "pg_hba.conf"
89 host all all 127.0.0.1/32 trust
90 host all all ::1/128 trust"))
92 (define %default-postgres-ident
93 (plain-file "pg_ident.conf"
94 "# MAPNAME SYSTEM-USERNAME PG-USERNAME"))
96 (define %default-postgres-config
97 (mixed-text-file "postgresql.conf"
98 "log_destination = 'syslog'\n"
99 "hba_file = '" %default-postgres-hba "'\n"
100 "ident_file = '" %default-postgres-ident "'\n"))
102 (define %postgresql-accounts
103 (list (user-group (name "postgres") (system? #t))
108 (comment "PostgreSQL server user")
109 (home-directory "/var/empty")
110 (shell (file-append shadow "/sbin/nologin")))))
112 (define postgresql-activation
114 (($ <postgresql-configuration> postgresql port locale config-file data-directory)
116 (use-modules (guix build utils)
119 (let ((user (getpwnam "postgres"))
120 (initdb (string-append #$postgresql "/bin/initdb"))
124 (list (string-append "--locale=" #$locale))
126 ;; Create db state directory.
127 (mkdir-p #$data-directory)
128 (chown #$data-directory (passwd:uid user) (passwd:gid user))
130 ;; Drop privileges and init state directory in a new
131 ;; process. Wait for it to finish before proceeding.
132 (match (primitive-fork)
134 ;; Exit with a non-zero status code if an exception is thrown.
138 (setgid (passwd:gid user))
139 (setuid (passwd:uid user))
147 (primitive-exit 1))))
148 (pid (waitpid pid))))))))
150 (define postgresql-shepherd-service
152 (($ <postgresql-configuration> postgresql port locale config-file data-directory)
153 (let* ((pg_ctl-wrapper
154 ;; Wrapper script that switches to the 'postgres' user before
159 (use-modules (ice-9 match)
161 (match (command-line)
163 (let ((user (getpwnam "postgres"))
164 (pg_ctl #$(file-append postgresql "/bin/pg_ctl"))
165 (options (format #f "--config-file=~a -p ~d"
166 #$config-file #$port)))
167 (setgid (passwd:gid user))
168 (setuid (passwd:uid user))
169 (execl pg_ctl pg_ctl "-D" #$data-directory "-o" options
173 (invoke #$pg_ctl-wrapper #$@args)))))
174 (list (shepherd-service
175 (provision '(postgres))
176 (documentation "Run the PostgreSQL daemon.")
177 (requirement '(user-processes loopback syslogd))
178 (start (action "start"))
179 (stop (action "stop"))))))))
181 (define postgresql-service-type
182 (service-type (name 'postgresql)
184 (list (service-extension shepherd-root-service-type
185 postgresql-shepherd-service)
186 (service-extension activation-service-type
187 postgresql-activation)
188 (service-extension account-service-type
189 (const %postgresql-accounts))))
190 (default-value (postgresql-configuration))))
192 (define* (postgresql-service #:key (postgresql postgresql)
194 (locale "en_US.utf8")
195 (config-file %default-postgres-config)
196 (data-directory "/var/lib/postgresql/data"))
197 "Return a service that runs @var{postgresql}, the PostgreSQL database server.
199 The PostgreSQL daemon loads its runtime configuration from @var{config-file}
200 and stores the database cluster in @var{data-directory}."
201 (service postgresql-service-type
202 (postgresql-configuration
203 (postgresql postgresql)
206 (config-file config-file)
207 (data-directory data-directory))))
214 (define-record-type* <memcached-configuration>
215 memcached-configuration make-memcached-configuration
216 memcached-configuration?
217 (memcached memcached-configuration-memcached ;<package>
219 (interfaces memcached-configuration-interfaces
220 (default '("0.0.0.0")))
221 (tcp-port memcached-configuration-tcp-port
223 (udp-port memcached-configuration-udp-port
225 (additional-options memcached-configuration-additional-options
228 (define %memcached-accounts
229 (list (user-group (name "memcached") (system? #t))
234 (comment "Memcached server user")
235 (home-directory "/var/empty")
236 (shell (file-append shadow "/sbin/nologin")))))
238 (define memcached-activation
240 (use-modules (guix build utils))
241 (let ((user (getpwnam "memcached")))
242 (mkdir-p "/var/run/memcached")
243 (chown "/var/run/memcached"
244 (passwd:uid user) (passwd:gid user)))))
246 (define memcached-shepherd-service
248 (($ <memcached-configuration> memcached interfaces tcp-port udp-port
250 (with-imported-modules (source-module-closure
251 '((gnu build shepherd)))
252 (list (shepherd-service
253 (provision '(memcached))
254 (documentation "Run the Memcached daemon.")
255 (requirement '(user-processes loopback))
256 (modules '((gnu build shepherd)))
257 (start #~(make-forkexec-constructor
258 `(#$(file-append memcached "/bin/memcached")
259 "-l" #$(string-join interfaces ",")
260 "-p" #$(number->string tcp-port)
261 "-U" #$(number->string udp-port)
263 ;; Memcached changes to the memcached user prior to
264 ;; writing the pid file, so write it to a directory
265 ;; that memcached owns.
266 "-P" "/var/run/memcached/pid"
268 ,#$@additional-options)
269 #:log-file "/var/log/memcached"
270 #:pid-file "/var/run/memcached/pid"))
271 (stop #~(make-kill-destructor))))))))
273 (define memcached-service-type
274 (service-type (name 'memcached)
276 (list (service-extension shepherd-root-service-type
277 memcached-shepherd-service)
278 (service-extension activation-service-type
279 (const memcached-activation))
280 (service-extension account-service-type
281 (const %memcached-accounts))))
282 (default-value (memcached-configuration))))
289 (define %default-mongodb-configuration-file
292 "# GNU Guix: MongoDB default configuration file
294 pidFilePath: /var/run/mongodb/pid
296 dbPath: /var/lib/mongodb
300 (define-record-type* <mongodb-configuration>
301 mongodb-configuration make-mongodb-configuration
302 mongodb-configuration?
303 (mongodb mongodb-configuration-mongodb
305 (config-file mongodb-configuration-config-file
306 (default %default-mongodb-configuration-file))
307 (data-directory mongodb-configuration-data-directory
308 (default "/var/lib/mongodb")))
310 (define %mongodb-accounts
311 (list (user-group (name "mongodb") (system? #t))
316 (comment "Mongodb server user")
317 (home-directory "/var/lib/mongodb")
318 (shell (file-append shadow "/sbin/nologin")))))
320 (define mongodb-activation
322 (($ <mongodb-configuration> mongodb config-file data-directory)
324 (use-modules (guix build utils))
325 (let ((user (getpwnam "mongodb")))
330 (passwd:uid user) (passwd:gid user)))
331 '("/var/run/mongodb" #$data-directory)))))))
333 (define mongodb-shepherd-service
335 (($ <mongodb-configuration> mongodb config-file data-directory)
337 (provision '(mongodb))
338 (documentation "Run the Mongodb daemon.")
339 (requirement '(user-processes loopback))
340 (start #~(make-forkexec-constructor
341 `(,(string-append #$mongodb "/bin/mongod")
346 #:pid-file "/var/run/mongodb/pid"
347 #:log-file "/var/log/mongodb.log"))
348 (stop #~(make-kill-destructor))))))
350 (define mongodb-service-type
353 (description "Run the MongoDB document database server.")
355 (list (service-extension shepherd-root-service-type
357 mongodb-shepherd-service))
358 (service-extension activation-service-type
360 (service-extension account-service-type
361 (const %mongodb-accounts))))
363 (mongodb-configuration))))
370 (define-record-type* <mysql-configuration>
371 mysql-configuration make-mysql-configuration
373 (mysql mysql-configuration-mysql (default mariadb))
374 (port mysql-configuration-port (default 3306)))
376 (define %mysql-accounts
384 (home-directory "/var/empty")
385 (shell (file-append shadow "/sbin/nologin")))))
387 (define mysql-configuration-file
389 (($ <mysql-configuration> mysql port)
390 (mixed-text-file "my.cnf" "[mysqld]
391 datadir=/var/lib/mysql
392 socket=/run/mysqld/mysqld.sock
393 port=" (number->string port) "
396 (define (%mysql-activation config)
397 "Return an activation gexp for the MySQL or MariaDB database server."
398 (let ((mysql (mysql-configuration-mysql config))
399 (my.cnf (mysql-configuration-file config)))
401 (use-modules (ice-9 popen)
403 (let* ((mysqld (string-append #$mysql "/bin/mysqld"))
404 (user (getpwnam "mysql"))
405 (uid (passwd:uid user))
406 (gid (passwd:gid user))
407 (datadir "/var/lib/mysql")
408 (rundir "/run/mysqld"))
410 (chown datadir uid gid)
412 (chown rundir uid gid)
413 ;; Initialize the database when it doesn't exist.
414 (when (not (file-exists? (string-append datadir "/mysql")))
415 (if (string-prefix? "mysql-" (strip-store-file-name #$mysql))
418 (string-append "--defaults-file=" #$my.cnf)
422 ;; XXX: The 'mysql_install_db' script doesn't work directly
423 ;; due to missing 'mkdir' in PATH.
424 (let ((p (open-pipe* OPEN_WRITE mysqld
426 "--defaults-file=" #$my.cnf)
429 ;; Create the system database, as does by 'mysql_install_db'.
430 (display "create database mysql;\n" p)
431 (display "use mysql;\n" p)
434 (call-with-input-file
435 (string-append #$mysql "/share/mysql/" sql)
436 (lambda (in) (dump-port in p))))
437 '("mysql_system_tables.sql"
438 "mysql_performance_tables.sql"
439 "mysql_system_tables_data.sql"
440 "fill_help_tables.sql"))
441 ;; Remove the anonymous user and disable root access from
442 ;; remote machines, as does by 'mysql_secure_installation'.
444 DELETE FROM user WHERE User='';
445 DELETE FROM user WHERE User='root' AND
446 Host NOT IN ('localhost', '127.0.0.1', '::1');
449 (close-pipe p))))))))
451 (define (mysql-shepherd-service config)
452 (list (shepherd-service
454 (documentation "Run the MySQL server.")
455 (start (let ((mysql (mysql-configuration-mysql config))
456 (my.cnf (mysql-configuration-file config)))
457 #~(make-forkexec-constructor
458 (list (string-append #$mysql "/bin/mysqld")
459 (string-append "--defaults-file=" #$my.cnf))
460 #:user "mysql" #:group "mysql")))
461 (stop #~(make-kill-destructor)))))
463 (define mysql-service-type
467 (list (service-extension account-service-type
468 (const %mysql-accounts))
469 (service-extension activation-service-type
471 (service-extension shepherd-root-service-type
472 mysql-shepherd-service)))))
474 (define* (mysql-service #:key (config (mysql-configuration)))
475 "Return a service that runs @command{mysqld}, the MySQL or MariaDB
478 The optional @var{config} argument specifies the configuration for
479 @command{mysqld}, which should be a @code{<mysql-configuration>} object."
480 (service mysql-service-type config))
487 (define-record-type* <redis-configuration>
488 redis-configuration make-redis-configuration
490 (redis redis-configuration-redis ;<package>
492 (bind redis-configuration-bind
493 (default "127.0.0.1"))
494 (port redis-configuration-port
496 (working-directory redis-configuration-working-directory
497 (default "/var/lib/redis"))
498 (config-file redis-configuration-config-file
501 (define (default-redis.conf bind port working-directory)
502 (mixed-text-file "redis.conf"
504 "port " (number->string port) "\n"
505 "dir " working-directory "\n"
508 (define %redis-accounts
509 (list (user-group (name "redis") (system? #t))
514 (comment "Redis server user")
515 (home-directory "/var/empty")
516 (shell (file-append shadow "/sbin/nologin")))))
518 (define redis-activation
520 (($ <redis-configuration> redis bind port working-directory config-file)
522 (use-modules (guix build utils)
525 (let ((user (getpwnam "redis")))
526 (mkdir-p #$working-directory)
527 (chown #$working-directory (passwd:uid user) (passwd:gid user)))))))
529 (define redis-shepherd-service
531 (($ <redis-configuration> redis bind port working-directory config-file)
534 (default-redis.conf bind port working-directory))))
535 (list (shepherd-service
537 (documentation "Run the Redis daemon.")
538 (requirement '(user-processes syslogd))
539 (start #~(make-forkexec-constructor
540 '(#$(file-append redis "/bin/redis-server")
544 (stop #~(make-kill-destructor))))))))
546 (define redis-service-type
547 (service-type (name 'redis)
549 (list (service-extension shepherd-root-service-type
550 redis-shepherd-service)
551 (service-extension activation-service-type
553 (service-extension account-service-type
554 (const %redis-accounts))))))