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>
6 ;;; This file is part of GNU Guix.
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.
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.
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/>.
21 (define-module (gnu services databases)
22 #:use-module (gnu services)
23 #:use-module (gnu services shepherd)
24 #:use-module (gnu system shadow)
25 #:use-module (gnu packages admin)
26 #:use-module (gnu packages databases)
27 #:use-module (guix records)
28 #:use-module (guix gexp)
29 #:use-module (ice-9 match)
30 #:export (postgresql-configuration
31 postgresql-configuration?
33 postgresql-service-type
38 mysql-configuration?))
42 ;;; Database services.
46 (define-record-type* <postgresql-configuration>
47 postgresql-configuration make-postgresql-configuration
48 postgresql-configuration?
49 (postgresql postgresql-configuration-postgresql ;<package>
51 (config-file postgresql-configuration-file)
52 (data-directory postgresql-configuration-data-directory))
54 (define %default-postgres-hba
55 (plain-file "pg_hba.conf"
58 host all all 127.0.0.1/32 trust
59 host all all ::1/128 trust"))
61 (define %default-postgres-ident
62 (plain-file "pg_ident.conf"
63 "# MAPNAME SYSTEM-USERNAME PG-USERNAME"))
65 (define %default-postgres-config
66 (mixed-text-file "postgresql.conf"
67 "log_destination = 'syslog'\n"
68 "hba_file = '" %default-postgres-hba "'\n"
69 "ident_file = '" %default-postgres-ident "'\n"))
71 (define %postgresql-accounts
72 (list (user-group (name "postgres") (system? #t))
77 (comment "PostgreSQL server user")
78 (home-directory "/var/empty")
79 (shell #~(string-append #$shadow "/sbin/nologin")))))
81 (define postgresql-activation
83 (($ <postgresql-configuration> postgresql config-file data-directory)
85 (use-modules (guix build utils)
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))
94 ;; Drop privileges and init state directory in a new
95 ;; process. Wait for it to finish before proceeding.
96 (match (primitive-fork)
98 ;; Exit with a non-zero status code if an exception is thrown.
102 (setgid (passwd:gid user))
103 (setuid (passwd:uid user))
104 (primitive-exit (system* initdb "-D" #$data-directory)))
106 (primitive-exit 1))))
107 (pid (waitpid pid))))))))
109 (define postgresql-shepherd-service
111 (($ <postgresql-configuration> postgresql config-file data-directory)
113 ;; Wrapper script that switches to the 'postgres' user before
115 (program-file "start-postgres"
116 #~(let ((user (getpwnam "postgres"))
117 (postgres (string-append #$postgresql
119 (setgid (passwd:gid user))
120 (setuid (passwd:uid user))
122 (string-append "--config-file="
124 "-D" #$data-directory)))))
125 (list (shepherd-service
126 (provision '(postgres))
127 (documentation "Run the PostgreSQL daemon.")
128 (requirement '(user-processes loopback syslogd))
129 (start #~(make-forkexec-constructor #$start-script))
130 (stop #~(make-kill-destructor))))))))
132 (define postgresql-service-type
133 (service-type (name 'postgresql)
135 (list (service-extension shepherd-root-service-type
136 postgresql-shepherd-service)
137 (service-extension activation-service-type
138 postgresql-activation)
139 (service-extension account-service-type
140 (const %postgresql-accounts))))))
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.
147 The PostgreSQL daemon loads its runtime configuration from @var{config-file}
148 and stores the database cluster in @var{data-directory}."
149 (service postgresql-service-type
150 (postgresql-configuration
151 (postgresql postgresql)
152 (config-file config-file)
153 (data-directory data-directory))))
160 (define-record-type* <mysql-configuration>
161 mysql-configuration make-mysql-configuration
163 (mysql mysql-configuration-mysql (default mariadb)))
165 (define %mysql-accounts
173 (home-directory "/var/empty")
174 (shell #~(string-append #$shadow "/sbin/nologin")))))
176 (define mysql-configuration-file
178 (($ <mysql-configuration> mysql)
179 (plain-file "my.cnf" "[mysqld]
180 datadir=/var/lib/mysql
181 socket=/run/mysqld/mysqld.sock
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)))
189 (use-modules (ice-9 popen)
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"))
198 (chown datadir uid gid)
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))
206 (string-append "--defaults-file=" #$my.cnf)
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
214 "--defaults-file=" #$my.cnf)
217 ;; Create the system database, as does by 'mysql_install_db'.
218 (display "create database mysql;\n" p)
219 (display "use mysql;\n" p)
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'.
232 DELETE FROM user WHERE User='';
233 DELETE FROM user WHERE User='root' AND
234 Host NOT IN ('localhost', '127.0.0.1', '::1');
237 (close-pipe p))))))))
239 (define (mysql-shepherd-service config)
240 (list (shepherd-service
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)))))
251 (define mysql-service-type
255 (list (service-extension account-service-type
256 (const %mysql-accounts))
257 (service-extension activation-service-type
259 (service-extension shepherd-root-service-type
260 mysql-shepherd-service)))))
262 (define* (mysql-service #:key (config (mysql-configuration)))
263 "Return a service that runs @command{mysqld}, the MySQL or MariaDB
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))