databases.scm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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>
  5. ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; 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 modules)
  28. #:use-module (guix records)
  29. #:use-module (guix gexp)
  30. #:use-module (ice-9 match)
  31. #:export (postgresql-configuration
  32. postgresql-configuration?
  33. postgresql-service
  34. postgresql-service-type
  35. memcached-service-type
  36. <memcached-configuration>
  37. memcached-configuration
  38. memcached-configuration?
  39. memcached-configuration-memecached
  40. memcached-configuration-interfaces
  41. memcached-configuration-tcp-port
  42. memcached-configuration-udp-port
  43. memcached-configuration-additional-options
  44. <mongodb-configuration>
  45. mongodb-configuration
  46. mongodb-configuration?
  47. mongodb-configuration-mongodb
  48. mongodb-configuration-config-file
  49. mongodb-configuration-data-directory
  50. mongodb-service-type
  51. mysql-service
  52. mysql-service-type
  53. mysql-configuration
  54. mysql-configuration?
  55. redis-configuration
  56. redis-configuration?
  57. redis-service-type))
  58. ;;; Commentary:
  59. ;;;
  60. ;;; Database services.
  61. ;;;
  62. ;;; Code:
  63. (define-record-type* <postgresql-configuration>
  64. postgresql-configuration make-postgresql-configuration
  65. postgresql-configuration?
  66. (postgresql postgresql-configuration-postgresql ;<package>
  67. (default postgresql))
  68. (port postgresql-configuration-port
  69. (default 5432))
  70. (locale postgresql-configuration-locale
  71. (default "en_US.utf8"))
  72. (config-file postgresql-configuration-file)
  73. (data-directory postgresql-configuration-data-directory))
  74. (define %default-postgres-hba
  75. (plain-file "pg_hba.conf"
  76. "
  77. local all all trust
  78. host all all 127.0.0.1/32 trust
  79. host all all ::1/128 trust"))
  80. (define %default-postgres-ident
  81. (plain-file "pg_ident.conf"
  82. "# MAPNAME SYSTEM-USERNAME PG-USERNAME"))
  83. (define %default-postgres-config
  84. (mixed-text-file "postgresql.conf"
  85. "log_destination = 'syslog'\n"
  86. "hba_file = '" %default-postgres-hba "'\n"
  87. "ident_file = '" %default-postgres-ident "'\n"))
  88. (define %postgresql-accounts
  89. (list (user-group (name "postgres") (system? #t))
  90. (user-account
  91. (name "postgres")
  92. (group "postgres")
  93. (system? #t)
  94. (comment "PostgreSQL server user")
  95. (home-directory "/var/empty")
  96. (shell (file-append shadow "/sbin/nologin")))))
  97. (define postgresql-activation
  98. (match-lambda
  99. (($ <postgresql-configuration> postgresql port locale config-file data-directory)
  100. #~(begin
  101. (use-modules (guix build utils)
  102. (ice-9 match))
  103. (let ((user (getpwnam "postgres"))
  104. (initdb (string-append #$postgresql "/bin/initdb"))
  105. (initdb-args
  106. (append
  107. (if #$locale
  108. (list (string-append "--locale=" #$locale))
  109. '()))))
  110. ;; Create db state directory.
  111. (mkdir-p #$data-directory)
  112. (chown #$data-directory (passwd:uid user) (passwd:gid user))
  113. ;; Drop privileges and init state directory in a new
  114. ;; process. Wait for it to finish before proceeding.
  115. (match (primitive-fork)
  116. (0
  117. ;; Exit with a non-zero status code if an exception is thrown.
  118. (dynamic-wind
  119. (const #t)
  120. (lambda ()
  121. (setgid (passwd:gid user))
  122. (setuid (passwd:uid user))
  123. (primitive-exit
  124. (apply system*
  125. initdb
  126. "-D"
  127. #$data-directory
  128. initdb-args)))
  129. (lambda ()
  130. (primitive-exit 1))))
  131. (pid (waitpid pid))))))))
  132. (define postgresql-shepherd-service
  133. (match-lambda
  134. (($ <postgresql-configuration> postgresql port locale config-file data-directory)
  135. (let ((start-script
  136. ;; Wrapper script that switches to the 'postgres' user before
  137. ;; launching daemon.
  138. (program-file "start-postgres"
  139. #~(let ((user (getpwnam "postgres"))
  140. (postgres (string-append #$postgresql
  141. "/bin/postgres")))
  142. (setgid (passwd:gid user))
  143. (setuid (passwd:uid user))
  144. (system* postgres
  145. (string-append "--config-file="
  146. #$config-file)
  147. "-p" (number->string #$port)
  148. "-D" #$data-directory)))))
  149. (list (shepherd-service
  150. (provision '(postgres))
  151. (documentation "Run the PostgreSQL daemon.")
  152. (requirement '(user-processes loopback syslogd))
  153. (start #~(make-forkexec-constructor #$start-script))
  154. (stop #~(make-kill-destructor))))))))
  155. (define postgresql-service-type
  156. (service-type (name 'postgresql)
  157. (extensions
  158. (list (service-extension shepherd-root-service-type
  159. postgresql-shepherd-service)
  160. (service-extension activation-service-type
  161. postgresql-activation)
  162. (service-extension account-service-type
  163. (const %postgresql-accounts))))))
  164. (define* (postgresql-service #:key (postgresql postgresql)
  165. (port 5432)
  166. (locale "en_US.utf8")
  167. (config-file %default-postgres-config)
  168. (data-directory "/var/lib/postgresql/data"))
  169. "Return a service that runs @var{postgresql}, the PostgreSQL database server.
  170. The PostgreSQL daemon loads its runtime configuration from @var{config-file}
  171. and stores the database cluster in @var{data-directory}."
  172. (service postgresql-service-type
  173. (postgresql-configuration
  174. (postgresql postgresql)
  175. (port port)
  176. (locale locale)
  177. (config-file config-file)
  178. (data-directory data-directory))))
  179. ;;;
  180. ;;; Memcached
  181. ;;;
  182. (define-record-type* <memcached-configuration>
  183. memcached-configuration make-memcached-configuration
  184. memcached-configuration?
  185. (memcached memcached-configuration-memcached ;<package>
  186. (default memcached))
  187. (interfaces memcached-configuration-interfaces
  188. (default '("0.0.0.0")))
  189. (tcp-port memcached-configuration-tcp-port
  190. (default 11211))
  191. (udp-port memcached-configuration-udp-port
  192. (default 11211))
  193. (additional-options memcached-configuration-additional-options
  194. (default '())))
  195. (define %memcached-accounts
  196. (list (user-group (name "memcached") (system? #t))
  197. (user-account
  198. (name "memcached")
  199. (group "memcached")
  200. (system? #t)
  201. (comment "Memcached server user")
  202. (home-directory "/var/empty")
  203. (shell (file-append shadow "/sbin/nologin")))))
  204. (define memcached-activation
  205. #~(begin
  206. (use-modules (guix build utils))
  207. (let ((user (getpwnam "memcached")))
  208. (mkdir-p "/var/run/memcached")
  209. (chown "/var/run/memcached"
  210. (passwd:uid user) (passwd:gid user)))))
  211. (define memcached-shepherd-service
  212. (match-lambda
  213. (($ <memcached-configuration> memcached interfaces tcp-port udp-port
  214. additional-options)
  215. (with-imported-modules (source-module-closure
  216. '((gnu build shepherd)))
  217. (list (shepherd-service
  218. (provision '(memcached))
  219. (documentation "Run the Memcached daemon.")
  220. (requirement '(user-processes loopback))
  221. (modules '((gnu build shepherd)))
  222. (start #~(make-forkexec-constructor
  223. `(#$(file-append memcached "/bin/memcached")
  224. "-l" #$(string-join interfaces ",")
  225. "-p" #$(number->string tcp-port)
  226. "-U" #$(number->string udp-port)
  227. "--daemon"
  228. ;; Memcached changes to the memcached user prior to
  229. ;; writing the pid file, so write it to a directory
  230. ;; that memcached owns.
  231. "-P" "/var/run/memcached/pid"
  232. "-u" "memcached"
  233. ,#$@additional-options)
  234. #:log-file "/var/log/memcached"
  235. #:pid-file "/var/run/memcached/pid"))
  236. (stop #~(make-kill-destructor))))))))
  237. (define memcached-service-type
  238. (service-type (name 'memcached)
  239. (extensions
  240. (list (service-extension shepherd-root-service-type
  241. memcached-shepherd-service)
  242. (service-extension activation-service-type
  243. (const memcached-activation))
  244. (service-extension account-service-type
  245. (const %memcached-accounts))))
  246. (default-value (memcached-configuration))))
  247. ;;;
  248. ;;; MongoDB
  249. ;;;
  250. (define %default-mongodb-configuration-file
  251. (plain-file
  252. "mongodb.yaml"
  253. "# GNU Guix: MongoDB default configuration file
  254. processManagement:
  255. pidFilePath: /var/run/mongodb/pid
  256. storage:
  257. dbPath: /var/lib/mongodb
  258. "))
  259. (define-record-type* <mongodb-configuration>
  260. mongodb-configuration make-mongodb-configuration
  261. mongodb-configuration?
  262. (mongodb mongodb-configuration-mongodb
  263. (default mongodb))
  264. (config-file mongodb-configuration-config-file
  265. (default %default-mongodb-configuration-file))
  266. (data-directory mongodb-configuration-data-directory
  267. (default "/var/lib/mongodb")))
  268. (define %mongodb-accounts
  269. (list (user-group (name "mongodb") (system? #t))
  270. (user-account
  271. (name "mongodb")
  272. (group "mongodb")
  273. (system? #t)
  274. (comment "Mongodb server user")
  275. (home-directory "/var/lib/mongodb")
  276. (shell (file-append shadow "/sbin/nologin")))))
  277. (define mongodb-activation
  278. (match-lambda
  279. (($ <mongodb-configuration> mongodb config-file data-directory)
  280. #~(begin
  281. (use-modules (guix build utils))
  282. (let ((user (getpwnam "mongodb")))
  283. (for-each
  284. (lambda (directory)
  285. (mkdir-p directory)
  286. (chown directory
  287. (passwd:uid user) (passwd:gid user)))
  288. '("/var/run/mongodb" #$data-directory)))))))
  289. (define mongodb-shepherd-service
  290. (match-lambda
  291. (($ <mongodb-configuration> mongodb config-file data-directory)
  292. (shepherd-service
  293. (provision '(mongodb))
  294. (documentation "Run the Mongodb daemon.")
  295. (requirement '(user-processes loopback))
  296. (start #~(make-forkexec-constructor
  297. `(,(string-append #$mongodb "/bin/mongod")
  298. "--config"
  299. ,#$config-file)
  300. #:user "mongodb"
  301. #:group "mongodb"
  302. #:pid-file "/var/run/mongodb/pid"
  303. #:log-file "/var/log/mongodb.log"))
  304. (stop #~(make-kill-destructor))))))
  305. (define mongodb-service-type
  306. (service-type
  307. (name 'mongodb)
  308. (description "Run the MongoDB document database server.")
  309. (extensions
  310. (list (service-extension shepherd-root-service-type
  311. (compose list
  312. mongodb-shepherd-service))
  313. (service-extension activation-service-type
  314. mongodb-activation)
  315. (service-extension account-service-type
  316. (const %mongodb-accounts))))
  317. (default-value
  318. (mongodb-configuration))))
  319. ;;;
  320. ;;; MySQL.
  321. ;;;
  322. (define-record-type* <mysql-configuration>
  323. mysql-configuration make-mysql-configuration
  324. mysql-configuration?
  325. (mysql mysql-configuration-mysql (default mariadb))
  326. (port mysql-configuration-port (default 3306)))
  327. (define %mysql-accounts
  328. (list (user-group
  329. (name "mysql")
  330. (system? #t))
  331. (user-account
  332. (name "mysql")
  333. (group "mysql")
  334. (system? #t)
  335. (home-directory "/var/empty")
  336. (shell (file-append shadow "/sbin/nologin")))))
  337. (define mysql-configuration-file
  338. (match-lambda
  339. (($ <mysql-configuration> mysql port)
  340. (mixed-text-file "my.cnf" "[mysqld]
  341. datadir=/var/lib/mysql
  342. socket=/run/mysqld/mysqld.sock
  343. port=" (number->string port) "
  344. "))))
  345. (define (%mysql-activation config)
  346. "Return an activation gexp for the MySQL or MariaDB database server."
  347. (let ((mysql (mysql-configuration-mysql config))
  348. (my.cnf (mysql-configuration-file config)))
  349. #~(begin
  350. (use-modules (ice-9 popen)
  351. (guix build utils))
  352. (let* ((mysqld (string-append #$mysql "/bin/mysqld"))
  353. (user (getpwnam "mysql"))
  354. (uid (passwd:uid user))
  355. (gid (passwd:gid user))
  356. (datadir "/var/lib/mysql")
  357. (rundir "/run/mysqld"))
  358. (mkdir-p datadir)
  359. (chown datadir uid gid)
  360. (mkdir-p rundir)
  361. (chown rundir uid gid)
  362. ;; Initialize the database when it doesn't exist.
  363. (when (not (file-exists? (string-append datadir "/mysql")))
  364. (if (string-prefix? "mysql-" (strip-store-file-name #$mysql))
  365. ;; For MySQL.
  366. (system* mysqld
  367. (string-append "--defaults-file=" #$my.cnf)
  368. "--initialize"
  369. "--user=mysql")
  370. ;; For MariaDB.
  371. ;; XXX: The 'mysql_install_db' script doesn't work directly
  372. ;; due to missing 'mkdir' in PATH.
  373. (let ((p (open-pipe* OPEN_WRITE mysqld
  374. (string-append
  375. "--defaults-file=" #$my.cnf)
  376. "--bootstrap"
  377. "--user=mysql")))
  378. ;; Create the system database, as does by 'mysql_install_db'.
  379. (display "create database mysql;\n" p)
  380. (display "use mysql;\n" p)
  381. (for-each
  382. (lambda (sql)
  383. (call-with-input-file
  384. (string-append #$mysql "/share/mysql/" sql)
  385. (lambda (in) (dump-port in p))))
  386. '("mysql_system_tables.sql"
  387. "mysql_performance_tables.sql"
  388. "mysql_system_tables_data.sql"
  389. "fill_help_tables.sql"))
  390. ;; Remove the anonymous user and disable root access from
  391. ;; remote machines, as does by 'mysql_secure_installation'.
  392. (display "
  393. DELETE FROM user WHERE User='';
  394. DELETE FROM user WHERE User='root' AND
  395. Host NOT IN ('localhost', '127.0.0.1', '::1');
  396. FLUSH PRIVILEGES;
  397. " p)
  398. (close-pipe p))))))))
  399. (define (mysql-shepherd-service config)
  400. (list (shepherd-service
  401. (provision '(mysql))
  402. (documentation "Run the MySQL server.")
  403. (start (let ((mysql (mysql-configuration-mysql config))
  404. (my.cnf (mysql-configuration-file config)))
  405. #~(make-forkexec-constructor
  406. (list (string-append #$mysql "/bin/mysqld")
  407. (string-append "--defaults-file=" #$my.cnf))
  408. #:user "mysql" #:group "mysql")))
  409. (stop #~(make-kill-destructor)))))
  410. (define mysql-service-type
  411. (service-type
  412. (name 'mysql)
  413. (extensions
  414. (list (service-extension account-service-type
  415. (const %mysql-accounts))
  416. (service-extension activation-service-type
  417. %mysql-activation)
  418. (service-extension shepherd-root-service-type
  419. mysql-shepherd-service)))))
  420. (define* (mysql-service #:key (config (mysql-configuration)))
  421. "Return a service that runs @command{mysqld}, the MySQL or MariaDB
  422. database server.
  423. The optional @var{config} argument specifies the configuration for
  424. @command{mysqld}, which should be a @code{<mysql-configuration>} object."
  425. (service mysql-service-type config))
  426. ;;;
  427. ;;; Redis
  428. ;;;
  429. (define-record-type* <redis-configuration>
  430. redis-configuration make-redis-configuration
  431. redis-configuration?
  432. (redis redis-configuration-redis ;<package>
  433. (default redis))
  434. (bind redis-configuration-bind
  435. (default "127.0.0.1"))
  436. (port redis-configuration-port
  437. (default 6379))
  438. (working-directory redis-configuration-working-directory
  439. (default "/var/lib/redis"))
  440. (config-file redis-configuration-config-file
  441. (default #f)))
  442. (define (default-redis.conf bind port working-directory)
  443. (mixed-text-file "redis.conf"
  444. "bind " bind "\n"
  445. "port " (number->string port) "\n"
  446. "dir " working-directory "\n"
  447. "daemonize no\n"))
  448. (define %redis-accounts
  449. (list (user-group (name "redis") (system? #t))
  450. (user-account
  451. (name "redis")
  452. (group "redis")
  453. (system? #t)
  454. (comment "Redis server user")
  455. (home-directory "/var/empty")
  456. (shell (file-append shadow "/sbin/nologin")))))
  457. (define redis-activation
  458. (match-lambda
  459. (($ <redis-configuration> redis bind port working-directory config-file)
  460. #~(begin
  461. (use-modules (guix build utils)
  462. (ice-9 match))
  463. (let ((user (getpwnam "redis")))
  464. (mkdir-p #$working-directory)
  465. (chown #$working-directory (passwd:uid user) (passwd:gid user)))))))
  466. (define redis-shepherd-service
  467. (match-lambda
  468. (($ <redis-configuration> redis bind port working-directory config-file)
  469. (let ((config-file
  470. (or config-file
  471. (default-redis.conf bind port working-directory))))
  472. (list (shepherd-service
  473. (provision '(redis))
  474. (documentation "Run the Redis daemon.")
  475. (requirement '(user-processes syslogd))
  476. (start #~(make-forkexec-constructor
  477. '(#$(file-append redis "/bin/redis-server")
  478. #$config-file)
  479. #:user "redis"
  480. #:group "redis"))
  481. (stop #~(make-kill-destructor))))))))
  482. (define redis-service-type
  483. (service-type (name 'redis)
  484. (extensions
  485. (list (service-extension shepherd-root-service-type
  486. redis-shepherd-service)
  487. (service-extension activation-service-type
  488. redis-activation)
  489. (service-extension account-service-type
  490. (const %redis-accounts))))))