gnu: services: Add mysql-service.

Message ID 1465913611-5552-1-git-send-email-iyzsong@gmail.com
State New
Headers

Commit Message

宋文武 June 14, 2016, 2:13 p.m. UTC
  * gnu/services/database.scm (<mysql-configuration>): New record type.
(%mysql-accounts, mysql-service-type): New variables.
(mysql-configuration-file, %mysql-activation, mysql-shepherd-services)
(mysql-services): New procedures.
* doc/guix.texi (Database Services): Document it.
---
 doc/guix.texi              |  19 +++++++-
 gnu/services/databases.scm | 107 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 124 insertions(+), 2 deletions(-)
  

Comments

Ludovic Courtès June 15, 2016, 1:09 p.m. UTC | #1
Hello!

宋文武 <iyzsong@gmail.com> skribis:

> * gnu/services/database.scm (<mysql-configuration>): New record type.
> (%mysql-accounts, mysql-service-type): New variables.
> (mysql-configuration-file, %mysql-activation, mysql-shepherd-services)
> (mysql-services): New procedures.
> * doc/guix.texi (Database Services): Document it.

[...]

> +@deffn {Scheme Procedure} mysql-service [#:config (mysql-configuration)]
> +Return a service that runs @command{mysqld}, the MySQL database server.

s/MySQL/MySQL or MariaDB/

> +@deftp {Data Type} mysql-configuration
> +Data type representing the configuration of @var{mysql-service}.
> +
> +@table @asis
> +@item @code{mysql} (default: @var{mariadb})
> +Package object of the MySQL database server, can be either @var{mariadb}
> +or @var{mysql}.
> +@end table
> +@end deftp

Do you have plans to extend this type eventually?

> +(define (%mysql-activation config)

Please add a docstring.  IIUC it initializes the ‘mysql’ database for
user ‘mysql’, and that database contains configuration info, right?

Otherwise LGTM!

If you want, it would be awesome if you could come up with a (gnu tests
databases) module that would run a GuixSD with the mysql service, and
then spawn a mysql client to make sure the basics work as expected.

Thank you for working on it!

Ludo’.
  
=?utf-8?B?5a6L5paH5q2m?= June 15, 2016, 2:59 p.m. UTC | #2
ludo@gnu.org (Ludovic Courtès) writes:

> Hello!
>
> 宋文武 <iyzsong@gmail.com> skribis:
>
>> * gnu/services/database.scm (<mysql-configuration>): New record type.
>> (%mysql-accounts, mysql-service-type): New variables.
>> (mysql-configuration-file, %mysql-activation, mysql-shepherd-services)
>> (mysql-services): New procedures.
>> * doc/guix.texi (Database Services): Document it.
>
> [...]
>
>> +@deffn {Scheme Procedure} mysql-service [#:config (mysql-configuration)]
>> +Return a service that runs @command{mysqld}, the MySQL database server.
>
> s/MySQL/MySQL or MariaDB/
OK.

>
>> +@deftp {Data Type} mysql-configuration
>> +Data type representing the configuration of @var{mysql-service}.
>> +
>> +@table @asis
>> +@item @code{mysql} (default: @var{mariadb})
>> +Package object of the MySQL database server, can be either @var{mariadb}
>> +or @var{mysql}.
>> +@end table
>> +@end deftp
>
> Do you have plans to extend this type eventually?
Not yet, should I use a simple keywoard argument instead?

>
>> +(define (%mysql-activation config)
>
> Please add a docstring.  IIUC it initializes the ‘mysql’ database for
> user ‘mysql’, and that database contains configuration info, right?
Yes, it does what ‘mysql_install_db’ and ‘mysql_secure_installation’
do (which doesn’t work directly now due to missing coreutils, etc.
in PATH).

And now I realize that this doesn't work for mysql,
I need to rename this to ‘%mariadb-activation’ and write
another ‘%mysql-activation’.

>
> Otherwise LGTM!
>
> If you want, it would be awesome if you could come up with a (gnu tests
> databases) module that would run a GuixSD with the mysql service, and
> then spawn a mysql client to make sure the basics work as expected.
>
Sure, I’ll look that later.
  
Ludovic Courtès June 16, 2016, 10:58 a.m. UTC | #3
iyzsong@member.fsf.org (宋文武) skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> Hello!
>>
>> 宋文武 <iyzsong@gmail.com> skribis:

[...]

>>> +@deftp {Data Type} mysql-configuration
>>> +Data type representing the configuration of @var{mysql-service}.
>>> +
>>> +@table @asis
>>> +@item @code{mysql} (default: @var{mariadb})
>>> +Package object of the MySQL database server, can be either @var{mariadb}
>>> +or @var{mysql}.
>>> +@end table
>>> +@end deftp
>>
>> Do you have plans to extend this type eventually?
> Not yet, should I use a simple keywoard argument instead?

No, that’s fine, just wondering.

>>> +(define (%mysql-activation config)
>>
>> Please add a docstring.  IIUC it initializes the ‘mysql’ database for
>> user ‘mysql’, and that database contains configuration info, right?
> Yes, it does what ‘mysql_install_db’ and ‘mysql_secure_installation’
> do (which doesn’t work directly now due to missing coreutils, etc.
> in PATH).

OK, would be worth mentioning in a comment.

> And now I realize that this doesn't work for mysql,
> I need to rename this to ‘%mariadb-activation’ and write
> another ‘%mysql-activation’.

Oh, then maybe an additional configuration knob is needed to choose
between MariaDB and MySQL?

Thanks,
Ludo’.
  

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 46d9e77..e163f36 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7985,7 +7985,7 @@  web site} for more information.
 @node Database Services
 @subsubsection Database Services
 
-The @code{(gnu services databases)} module provides the following service.
+The @code{(gnu services databases)} module provides the following services.
 
 @deffn {Scheme Procedure} postgresql-service [#:postgresql postgresql] @
        [#:config-file] [#:data-directory ``/var/lib/postgresql/data'']
@@ -7997,6 +7997,23 @@  The PostgreSQL daemon loads its runtime configuration from
 @var{data-directory}.
 @end deffn
 
+@deffn {Scheme Procedure} mysql-service [#:config (mysql-configuration)]
+Return a service that runs @command{mysqld}, the MySQL database server.
+
+The optional @var{config} argument specifies the configuration for
+@command{mysqld}, which should be a @code{<mysql-configuraiton>} object.
+@end deffn
+
+@deftp {Data Type} mysql-configuration
+Data type representing the configuration of @var{mysql-service}.
+
+@table @asis
+@item @code{mysql} (default: @var{mariadb})
+Package object of the MySQL database server, can be either @var{mariadb}
+or @var{mysql}.
+@end table
+@end deftp
+
 @node Mail Services
 @subsubsection Mail Services
 
diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm
index 690375e..fb063da 100644
--- a/gnu/services/databases.scm
+++ b/gnu/services/databases.scm
@@ -27,7 +27,9 @@ 
   #:use-module (guix records)
   #:use-module (guix gexp)
   #:use-module (ice-9 match)
-  #:export (postgresql-service))
+  #:export (postgresql-service
+            mysql-service
+            mysql-configuration))
 
 ;;; Commentary:
 ;;;
@@ -143,3 +145,106 @@  and stores the database cluster in @var{data-directory}."
             (postgresql postgresql)
             (config-file config-file)
             (data-directory data-directory))))
+
+
+;;;
+;;; MySQL.
+;;;
+
+(define-record-type* <mysql-configuration>
+  mysql-configuration make-mysql-configuration
+  mysql-configuration?
+  (mysql mysql-configuration-mysql (default mariadb)))
+
+(define %mysql-accounts
+  (list (user-group
+         (name "mysql")
+         (system? #t))
+        (user-account
+         (name "mysql")
+         (group "mysql")
+         (system? #t)
+         (home-directory "/var/empty")
+         (shell #~(string-append #$shadow "/sbin/nologin")))))
+
+(define mysql-configuration-file
+  (match-lambda
+    (($ <mysql-configuration> mysql)
+     (plain-file "my.cnf" "[mysqld]
+datadir=/var/lib/mysql
+socket=/run/mysqld/mysqld.sock
+"))))
+
+(define (%mysql-activation config)
+  (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")))
+            (let ((p (open-pipe* OPEN_WRITE mysqld
+                                 (string-append "--defaults-file=" #$my.cnf)
+                                 "--bootstrap"
+                                 "--user=mysql")))
+              ;; Create the system database, according to '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 "/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, according to '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-shepherd-service config)
+  (list (shepherd-service
+         (provision '(mysql))
+         (documentation "Run the MySQL server.")
+         (start (let ((mysql  (mysql-configuration-mysql 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")))
+         (stop #~(make-kill-destructor)))))
+
+(define mysql-service-type
+  (service-type
+   (name 'mysql)
+   (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-service)))))
+
+(define* (mysql-service #:key (config (mysql-configuration)))
+  "Return a service that runs @command{mysqld}, the MySQL database server.
+
+The optional @var{config} argument specifies the configuration for
+@command{mysqld}, which should be a @code{<mysql-configuration>} object."
+  (service mysql-service-type config))