diff --git a/doc/guix.texi b/doc/guix.texi index bef42e160a..2a98dda324 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -19151,6 +19151,12 @@ Socket file to use for local (non-network) connections. @item @code{extra-content} (default: @code{""}) Additional settings for the @file{my.cnf} configuration file. +@item @code{auto-upgrade?} (default: @code{#t}) +Whether to automatically run @command{mysql_upgrade} after starting the +service. This is necessary to upgrade the @dfn{system schema} after +``major'' updates (such as switching from MariaDB 10.4 to 10.5), but can +be disabled if you would rather do that manually. + @end table @end deftp diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm index 5a88b70d74..60b31e0373 100644 --- a/gnu/services/databases.scm +++ b/gnu/services/databases.scm @@ -6,6 +6,7 @@ ;;; Copyright © 2018 Clément Lassieur ;;; Copyright © 2018 Julien Lepiller ;;; Copyright © 2019 Robert Vollmert +;;; Copyright © 2020 Marius Bakke ;;; ;;; This file is part of GNU Guix. ;;; @@ -468,7 +469,8 @@ storage: (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")) - (extra-content mysql-configuration-extra-content (default ""))) + (extra-content mysql-configuration-extra-content (default "")) + (auto-upgrade? mysql-configuration-auto-upgrade? (default #t))) (define %mysql-accounts (list (user-group @@ -559,6 +561,52 @@ FLUSH PRIVILEGES; #:user "mysql" #:group "mysql"))) (stop #~(make-kill-destructor))))) +(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 + ;; to run the upgrade script. + (program-file + "mysql-upgrade-wrapper" + #~(begin + (let ((mysql-upgrade #$(file-append mysql "/bin/mysql_upgrade")) + (timeout 10)) + (begin + (let loop ((i 0)) + (catch 'system-error + (lambda () + (let ((sock (socket PF_UNIX SOCK_STREAM 0))) + (connect sock AF_UNIX #$socket-file) + (close-port sock) + ;; The socket is ready! + (execl mysql-upgrade mysql-upgrade + (string-append "--socket=" #$socket-file)))) + (lambda args + (if (< i timeout) + (begin + (sleep 1) + (loop (+ 1 i))) + ;; No luck, give up. + (throw 'timeout-error + "MySQL server did not appear in time!")))))))))) + +(define (mysql-upgrade-shepherd-service config) + (list (shepherd-service + (provision '(mysql-upgrade)) + (requirement '(mysql)) + (one-shot? #t) + (documentation "Upgrade MySQL database schemas.") + (start (let ((mysql (mysql-configuration-mysql config)) + (socket (mysql-configuration-socket config))) + #~(make-forkexec-constructor + (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) + (mysql-upgrade-shepherd-service config)) + (mysql-shepherd-service config))) + (define mysql-service-type (service-type (name 'mysql) @@ -568,7 +616,7 @@ FLUSH PRIVILEGES; (service-extension activation-service-type %mysql-activation) (service-extension shepherd-root-service-type - mysql-shepherd-service))) + mysql-shepherd-services))) (default-value (mysql-configuration)))) (define-deprecated (mysql-service #:key (config (mysql-configuration))) diff --git a/gnu/tests/databases.scm b/gnu/tests/databases.scm index 1d7f53ec3e..dd1af1dbcc 100644 --- a/gnu/tests/databases.scm +++ b/gnu/tests/databases.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2017 Christopher Baines +;;; Copyright © 2020 Marius Bakke ;;; ;;; This file is part of GNU Guix. ;;; @@ -311,6 +312,9 @@ ((pid) (number? pid)))))) marionette)) + (test-assert "mysql_upgrade completed" + (wait-for-file "/var/lib/mysql/mysql_upgrade_info" marionette)) + (test-end) (exit (= (test-runner-fail-count (test-runner-current)) 0)))))