aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEllen Papsch <ep@stern-data.com>2021-06-21 15:27:52 +0200
committerMarius Bakke <marius@gnu.org>2022-11-20 17:54:04 +0100
commitc7b266fdf2754c139803c156677bf2828c78d072 (patch)
tree6fbeb793cb4e8c797062e69fc29960e4b7b760a2
parent96efebed249944be4f4ddfba53ca2f983e4d5e46 (diff)
downloadguix-c7b266fdf2754c139803c156677bf2828c78d072.tar.gz
guix-c7b266fdf2754c139803c156677bf2828c78d072.zip
gnu: mysql: Support custom data dir.
* gnu/services/databases.scm (mysql-configuration): Add datadir property. * gnu/services/databases.scm (mysql-configuration-file): Replace hard coded data dir with property from config. * gnu/services/databases.scm (%mysql-activation): Remove activation, it runs before PID 1. The data dir may reside on a file system not mounted at this time. * gnu/services/databases.scm (mysql-install-shepherd-service): Create service which replaces the activation. Provide mysql-install. * gnu/services/databases.scm (mysql-shepherd-service): Move invocation of mysqld to mysql-start program-file, because the invocation gotten more complex. Require mysql-install. * gnu/services/databases.scm (mysql-start): Invoke mysqld only if a lock file appears. * gnu/services/databases.scm (mysql-shepherd-services): Prepend the install service before the normal service. * gnu/services/databases.scm (mysql-upgrade-wrapper): Increase timeout to 20s to let the mysql install procedure finish. Signed-off-by: Marius Bakke <marius@gnu.org>
-rw-r--r--gnu/services/databases.scm187
1 files changed, 119 insertions, 68 deletions
diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm
index fb3cd3c478..cc9379792d 100644
--- a/gnu/services/databases.scm
+++ b/gnu/services/databases.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2019 Robert Vollmert <rob@vllmrt.net>
;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
;;; Copyright © 2021 David Larsson <david.larsson@selfhosted.xyz>
+;;; Copyright © 2021 Aljosha Papsch <ep@stern-data.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -532,6 +533,7 @@ applications.")))
(bind-address mysql-configuration-bind-address (default "127.0.0.1"))
(port mysql-configuration-port (default 3306))
(socket mysql-configuration-socket (default "/run/mysqld/mysqld.sock"))
+ (datadir mysql-configuration-datadir (default "/var/lib/mysql"))
(extra-content mysql-configuration-extra-content (default ""))
(extra-environment mysql-configuration-extra-environment (default #~'()))
(auto-upgrade? mysql-configuration-auto-upgrade? (default #t)))
@@ -549,85 +551,133 @@ applications.")))
(define mysql-configuration-file
(match-lambda
- (($ <mysql-configuration> mysql bind-address port socket extra-content)
+ (($ <mysql-configuration> mysql bind-address port socket datadir extra-content)
(mixed-text-file "my.cnf" "[mysqld]
-datadir=/var/lib/mysql
+datadir=" datadir "
socket=" socket "
bind-address=" bind-address "
port=" (number->string port) "
" extra-content "
"))))
-(define (%mysql-activation config)
- "Return an activation gexp for the MySQL or MariaDB database server."
- (let ((mysql (mysql-configuration-mysql config))
- (my.cnf (mysql-configuration-file config)))
- #~(begin
- (use-modules (ice-9 popen)
- (guix build utils))
- (let* ((mysqld (string-append #$mysql "/bin/mysqld"))
- (user (getpwnam "mysql"))
- (uid (passwd:uid user))
- (gid (passwd:gid user))
- (datadir "/var/lib/mysql")
- (rundir "/run/mysqld"))
- (mkdir-p datadir)
- (chown datadir uid gid)
- (mkdir-p rundir)
- (chown rundir uid gid)
- ;; Initialize the database when it doesn't exist.
- (when (not (file-exists? (string-append datadir "/mysql")))
- (if (string-prefix? "mysql-" (strip-store-file-name #$mysql))
- ;; For MySQL.
- (system* mysqld
- (string-append "--defaults-file=" #$my.cnf)
- "--initialize"
- "--user=mysql")
- ;; For MariaDB.
- ;; XXX: The 'mysql_install_db' script doesn't work directly
- ;; due to missing 'mkdir' in PATH.
- (let ((p (open-pipe* OPEN_WRITE mysqld
- (string-append
- "--defaults-file=" #$my.cnf)
- "--bootstrap"
- "--user=mysql")))
- ;; Create the system database, as does by 'mysql_install_db'.
- (display "create database mysql;\n" p)
- (display "use mysql;\n" p)
- (for-each
- (lambda (sql)
- (call-with-input-file
- (string-append #$mysql:lib "/share/mysql/" sql)
- (lambda (in) (dump-port in p))))
- '("mysql_system_tables.sql"
- "mysql_performance_tables.sql"
- "mysql_system_tables_data.sql"
- "fill_help_tables.sql"))
- ;; Remove the anonymous user and disable root access from
- ;; remote machines, as does by 'mysql_secure_installation'.
- (display "
-DELETE FROM user WHERE User='';
-DELETE FROM user WHERE User='root' AND
- Host NOT IN ('localhost', '127.0.0.1', '::1');
-FLUSH PRIVILEGES;
-" p)
- (close-pipe p))))))))
+(define (mysql-with-install-lock)
+ "Return a loop function which evals thunk when the install is locked."
+ #~(lambda (thunk)
+ (let loop ((i 0))
+ (let ((timeout 10)
+ (lock-stat (stat "/var/lib/mysql.lock" #f)))
+ (if (and (not (eq? lock-stat #f))
+ (eq? (stat:type lock-stat) 'regular))
+ (apply thunk '())
+ (if (< i timeout)
+ (begin
+ (sleep 1)
+ (loop (+ 1 i)))
+ (throw 'timeout-error
+ "MySQL installation not locked in time!")))))))
+
+(define (mysql-start config)
+ "Start mysqld if install lock file appears"
+ (program-file
+ "mysql-start"
+ (let ((mysql (mysql-configuration-mysql config))
+ (my.cnf (mysql-configuration-file config)))
+ #~(let ((mysqld (string-append #$mysql "/bin/mysqld"))
+ (with-lock #$(mysql-with-install-lock)))
+ (with-lock (lambda ()
+ (execl mysqld mysqld
+ (string-append "--defaults-file=" #$my.cnf))))))))
(define (mysql-shepherd-service config)
(list (shepherd-service
(provision '(mysql))
+ (requirement '(mysql-install))
(documentation "Run the MySQL server.")
- (start (let ((mysql (mysql-configuration-mysql config))
+ (start (let ((mysql (mysql-configuration-mysql config))
(extra-env (mysql-configuration-extra-environment config))
(my.cnf (mysql-configuration-file config)))
#~(make-forkexec-constructor
- (list (string-append #$mysql "/bin/mysqld")
- (string-append "--defaults-file=" #$my.cnf))
- #:user "mysql" #:group "mysql"
- #:log-file "/var/log/mysqld.log"
- #:environment-variables #$extra-env)))
+ (list #$(mysql-start config))
+ #:user "mysql" #:group "mysql"
+ #:log-file "/var/log/mysqld.log"
+ #:environment-variables #$extra-env)))
(stop #~(make-kill-destructor)))))
+(define (mysql-install config)
+ "Install MySQL system database and secure the installation."
+ (let ((mysql (mysql-configuration-mysql config))
+ (my.cnf (mysql-configuration-file config))
+ (datadir (mysql-configuration-datadir config))
+ (extra-env (mysql-configuration-extra-environment config)))
+ (program-file
+ "mysql-install"
+ (with-imported-modules (source-module-closure
+ '((ice-9 popen)
+ (guix build utils)))
+ #~(begin
+ (use-modules (ice-9 popen)
+ (guix build utils))
+ (let* ((mysqld (string-append #$mysql "/bin/mysqld"))
+ (user (getpwnam "mysql"))
+ (uid (passwd:uid user))
+ (gid (passwd:gid user))
+ (datadir #$datadir)
+ (rundir "/run/mysqld"))
+ (mkdir-p datadir)
+ (chown datadir uid gid)
+ (mkdir-p rundir)
+ (chown rundir uid gid)
+ ;; Initialize the database when it doesn't exist.
+ (when (not (file-exists? (string-append datadir "/mysql")))
+ (if (string-prefix? "mysql-" (strip-store-file-name #$mysql))
+ ;; For MySQL.
+ (system* mysqld
+ (string-append "--defaults-file=" #$my.cnf)
+ "--initialize"
+ "--user=mysql")
+ ;; For MariaDB.
+ ;; XXX: The 'mysql_install_db' script doesn't work directly
+ ;; due to missing 'mkdir' in PATH.
+ (let ((p (open-pipe* OPEN_WRITE mysqld
+ (string-append
+ "--defaults-file=" #$my.cnf)
+ "--bootstrap"
+ "--user=mysql")))
+ ;; Create the system database, as does by 'mysql_install_db'.
+ (display "create database mysql;\n" p)
+ (display "use mysql;\n" p)
+ (for-each
+ (lambda (sql)
+ (call-with-input-file
+ (string-append #$mysql:lib "/share/mysql/" sql)
+ (lambda (in) (dump-port in p))))
+ '("mysql_system_tables.sql"
+ "mysql_performance_tables.sql"
+ "mysql_system_tables_data.sql"
+ "fill_help_tables.sql"))
+ ;; Remove the anonymous user and disable root access from
+ ;; remote machines, as does by 'mysql_secure_installation'.
+ (display "
+DELETE FROM user WHERE User='';
+DELETE FROM user WHERE User='root' AND
+ Host NOT IN ('localhost', '127.0.0.1', '::1');
+FLUSH PRIVILEGES;
+" p)
+ (close-pipe p))))
+ (call-with-output-file "/var/lib/mysql.lock"
+ (lambda (p)
+ (write #t p)))))))))
+
+(define (mysql-install-shepherd-service config)
+ (list (shepherd-service
+ (provision '(mysql-install))
+ (requirement '(file-systems))
+ (one-shot? #t)
+ (documentation "Install MySQL system database and secure installation.")
+ (start #~(make-forkexec-constructor
+ (list #$(mysql-install config))
+ #:log-file "/var/log/mysqld-install.log")))))
+
(define (mysql-upgrade-wrapper mysql socket-file)
;; The MySQL socket and PID file may appear before the server is ready to
;; accept connections. Ensure the socket is responsive before attempting
@@ -636,7 +686,7 @@ FLUSH PRIVILEGES;
"mysql-upgrade-wrapper"
#~(begin
(let ((mysql-upgrade #$(file-append mysql "/bin/mysql_upgrade"))
- (timeout 10))
+ (timeout 20))
(begin
(let loop ((i 0))
(catch 'system-error
@@ -668,11 +718,14 @@ FLUSH PRIVILEGES;
(list #$(mysql-upgrade-wrapper mysql socket))
#:user "mysql" #:group "mysql"))))))
+
(define (mysql-shepherd-services config)
- (if (mysql-configuration-auto-upgrade? config)
- (append (mysql-shepherd-service config)
+ (let ((min-services (append (mysql-install-shepherd-service config)
+ (mysql-shepherd-service config))))
+ (if (mysql-configuration-auto-upgrade? config)
+ (append min-services
(mysql-upgrade-shepherd-service config))
- (mysql-shepherd-service config)))
+ min-services)))
(define mysql-service-type
(service-type
@@ -680,8 +733,6 @@ FLUSH PRIVILEGES;
(extensions
(list (service-extension account-service-type
(const %mysql-accounts))
- (service-extension activation-service-type
- %mysql-activation)
(service-extension shepherd-root-service-type
mysql-shepherd-services)))
(default-value (mysql-configuration))