GNU bug report logs - #49155
[PATCH] gnu: mysql: Support custom data dir.

Previous Next

Package: guix-patches;

Reported by: Aljosha Papsch <ep <at> stern-data.com>

Date: Mon, 21 Jun 2021 14:23:01 UTC

Severity: normal

Tags: patch

Done: Marius Bakke <marius <at> gnu.org>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 49155 in the body.
You can then email your comments to 49155 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#49155; Package guix-patches. (Mon, 21 Jun 2021 14:23:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Aljosha Papsch <ep <at> stern-data.com>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Mon, 21 Jun 2021 14:23:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Aljosha Papsch <ep <at> stern-data.com>
To: guix-patches <at> gnu.org
Cc: Ellen Papsch <ep <at> stern-data.com>
Subject: [PATCH] gnu: mysql: Support custom data dir.
Date: Mon, 21 Jun 2021 15:27:52 +0200
From: Ellen Papsch <ep <at> stern-data.com>

* 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.
---
 gnu/services/databases.scm | 187 +++++++++++++++++++++++--------------
 1 file changed, 119 insertions(+), 68 deletions(-)

diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm
index eba88cdb68..f8f78619d3 100644
--- a/gnu/services/databases.scm
+++ b/gnu/services/databases.scm
@@ -8,6 +8,7 @@
 ;;; Copyright © 2019 Robert Vollmert <rob <at> vllmrt.net>
 ;;; Copyright © 2020 Marius Bakke <marius <at> gnu.org>
 ;;; Copyright © 2021 David Larsson <david.larsson <at> selfhosted.xyz>
+;;; Copyright © 2021 Aljosha Papsch <ep <at> stern-data.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -527,6 +528,7 @@ created after the PostgreSQL database is started.")))
   (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)))
@@ -544,85 +546,133 @@ created after the PostgreSQL database is started.")))
 
 (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
@@ -631,7 +681,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
@@ -663,11 +713,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
@@ -675,8 +728,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))))
-- 
2.32.0





Reply sent to Marius Bakke <marius <at> gnu.org>:
You have taken responsibility. (Sun, 20 Nov 2022 16:57:01 GMT) Full text and rfc822 format available.

Notification sent to Aljosha Papsch <ep <at> stern-data.com>:
bug acknowledged by developer. (Sun, 20 Nov 2022 16:57:02 GMT) Full text and rfc822 format available.

Message #10 received at 49155-done <at> debbugs.gnu.org (full text, mbox):

From: Marius Bakke <marius <at> gnu.org>
To: Aljosha Papsch <ep <at> stern-data.com>, 49155-done <at> debbugs.gnu.org
Cc: Ellen Papsch <ep <at> stern-data.com>
Subject: Re: [bug#49155] [PATCH] gnu: mysql: Support custom data dir.
Date: Sun, 20 Nov 2022 17:56:12 +0100
[Message part 1 (text/plain, inline)]
Hi!

Thanks for the patch, and sorry for the slooow response...

Aljosha Papsch <ep <at> stern-data.com> skriver:

> From: Ellen Papsch <ep <at> stern-data.com>
>
> * 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.

I have finally applied this patch, along with a follow-up commit to make
the mysql-upgrade service also work with a custom datadir.

I also ended up dropping the 'mysql-install' service in favor of a
mysqld wrapper script that calls the mysql-install script at startup
when the "mysql" DB is missing.

Pushed in c7b266fdf2754c139803c156677bf2828c78d072.
[signature.asc (application/pgp-signature, inline)]

bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 19 Dec 2022 12:24:10 GMT) Full text and rfc822 format available.

This bug report was last modified 1 year and 126 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.