projects/guix·blob master · refs

231 lines · 9.3 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2018 Christopher Baines <[email protected]>
3;;; Copyright © 2025-2026 Artur Wroblewski <[email protected]>
4;;; Copyright © 2026 Mathieu Lirzin <[email protected]>
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21(define-module (gnu services high-availability)
22 #:use-module (gnu packages admin)
23 #:use-module (gnu packages erlang)
24 #:use-module (gnu packages high-availability)
25 #:use-module (gnu services)
26 #:use-module (gnu services configuration)
27 #:use-module (gnu services shepherd)
28 #:use-module (gnu system shadow)
29 #:use-module (guix gexp)
30 #:use-module (guix modules)
31 #:use-module (guix records)
32 #:use-module (ice-9 match)
33 #:use-module (ice-9 format)
34
35 #:export (epmd-configuration
36 epmd-configuration-fields
37 epmd-configuration?
38 epmd-configuration-user
39 epmd-configuration-group
40 epmd-configuration-address
41 epmd-configuration-port
42 epmd-service-type
43
44 rabbitmq-configuration
45 rabbitmq-configuration?
46 rabbitmq-configuration-rabbitmq
47 rabbitmq-configuration-node-name
48 rabbitmq-configuration-config-file
49 rabbitmq-configuration-env-config-file
50 rabbitmq-configuration-plugins
51 rabbitmq-service-type))
52
53(define-configuration/no-serialization epmd-configuration
54 (user (string "epmd") "The user running epmd.")
55 (group (string "epmd") "The user group running epmd.")
56 ;; The address default works for IPv4-only or IPv6-only systems. For example,
57 ;; epmd shows warning for ::1 on IPv4-only system, but starts anyway.
58 (address (list-of-strings (list "127.0.0.1" "::1"))
59 "List of addresses for epmd to listen on. Set it to false
60(@code{#f}) to listen on all available addresses. Note that epmd cannot start
61on @code{\"0.0.0.0\"} address.")
62 (port (integer 4369) "Default port for epmd to listen on."))
63
64(define (epmd-accounts config)
65 (match-record config <epmd-configuration> (user group)
66 (list (user-group (name group)
67 (system? #t))
68 (user-account (name user)
69 (group group)
70 (system? #t)
71 (comment "Erlang Port Mapper Daemon user")
72 (home-directory "/var/empty")
73 (shell (file-append shadow "/sbin/nologin"))))))
74
75(define (epmd-shepherd-service config)
76 (match-record config <epmd-configuration>
77 (address port)
78 (let ((address-list (if address (string-join address ",") #f)))
79 (with-imported-modules
80 (source-module-closure '((gnu build shepherd)))
81 (list
82 (shepherd-service
83 (provision '(epmd))
84 (documentation "Run the Erlang Port Mapper Daemon (epmd).")
85 (requirement '(user-processes loopback))
86 (modules '((gnu build shepherd)))
87 (start
88 #~(make-forkexec-constructor
89 (append (list #$(file-append erlang "/bin/epmd")
90 "-port"
91 #$(number->string port))
92 (if #$address-list
93 (list "-address" #$address-list)
94 (list)))
95 #:user "epmd"
96 #:group "epmd"))
97 (stop #~(make-kill-destructor))))))))
98
99(define epmd-service-type
100 (service-type
101 (name 'epmd)
102 (description "Run the Erlang Port Mapper Daemon (epmd).")
103 (extensions (list (service-extension shepherd-root-service-type
104 epmd-shepherd-service)
105 (service-extension account-service-type epmd-accounts)))
106 (default-value (epmd-configuration))))
107
108;; By default, start messaging and inter-node RabbitMQ listeners on local
109;; interfaces only, see also:
110;;
111;; https://www.rabbitmq.com/docs/networking
112;;
113;; NOTE: Enabling a RabbitMQ plugin will make it usually listen on a public
114;; interface.
115(define %default-rabbitmq-config-file
116 (plain-file "rabbitmq.conf" "
117listeners.tcp.1 = 127.0.0.1:5672
118listeners.tcp.2 = ::1:5672
119
120distribution.listener.interface = 127.0.0.1
121"))
122
123(define-record-type* <rabbitmq-configuration> rabbitmq-configuration
124 make-rabbitmq-configuration
125 rabbitmq-configuration?
126 (rabbitmq rabbitmq-configuration-rabbitmq
127 (default rabbitmq))
128 (node-name rabbitmq-configuration-node-name
129 (default "rabbit@localhost"))
130 (config-file rabbitmq-configuration-config-file
131 (default %default-rabbitmq-config-file))
132 (env-config-file rabbitmq-configuration-env-file (default #f))
133 ;; It can be a mnesia database or a khepri database, so use "data" instead
134 ;; of the traditional "mnesia".
135 (data-directory rabbitmq-configuration-data-directory
136 (default "/var/lib/rabbitmq/data"))
137 (plugins rabbitmq-configuration-plugins
138 (default '())))
139
140(define %rabbitmq-accounts
141 (list (user-group
142 (name "rabbitmq")
143 (system? #t))
144 (user-account
145 (name "rabbitmq")
146 (group "rabbitmq")
147 (system? #t)
148 (comment "RabbitMQ server user")
149 (home-directory "/var/lib/rabbitmq")
150 (shell (file-append shadow "/sbin/nologin")))))
151
152(define (rabbitmq-activation config)
153 (let* ((data-directory (rabbitmq-configuration-data-directory config))
154 (plugins (string-join (rabbitmq-configuration-plugins config) ",")))
155 (with-imported-modules '((guix build utils))
156 #~(begin
157 (use-modules (guix build utils))
158 (let ((user (getpwnam "rabbitmq"))
159 (srv-directories (list
160 "/var/lib/rabbitmq"
161 "/var/log/rabbitmq"
162 "/var/run/rabbitmq"
163 #$data-directory)))
164 (for-each (lambda (directory)
165 (mkdir-p directory)
166 (chown directory
167 (passwd:uid user)
168 (passwd:gid user)))
169 srv-directories)
170
171 ;; Create file with the enabled plugins.
172 (with-output-to-file (string-append #$data-directory
173 "/enabled_plugins")
174 (lambda () (display (format #f "[~a]." #$plugins))))
175 (chown (string-append #$data-directory "/enabled_plugins")
176 (passwd:uid user)
177 (passwd:gid user)))))))
178
179(define (rabbitmq-shepherd-service config)
180 (match-record config <rabbitmq-configuration>
181 (rabbitmq node-name data-directory config-file env-config-file plugins)
182 (with-imported-modules
183 (source-module-closure '((gnu build shepherd)))
184 (list
185 (shepherd-service
186 (provision '(rabbitmq))
187 (documentation "Run the RabbitMQ daemon.")
188 (requirement '(epmd))
189 (modules '((gnu build shepherd)))
190 (start
191 #~(make-forkexec-constructor
192 `(#$(file-append rabbitmq "/sbin/rabbitmq-server"))
193 #:pid-file "/var/run/rabbitmq/pid"
194 #:user "rabbitmq"
195 #:group "rabbitmq"
196 #:environment-variables
197 (append
198 (if #$env-config-file
199 (list (string-append "RABBITMQ_CONF_ENV_FILE="
200 #$env-config-file))
201 (list))
202 (list
203 (string-append "RABBITMQ_NODENAME=" #$node-name)
204 (string-append "RABBITMQ_CONFIG_FILE=" #$config-file)
205 "RABBITMQ_PID_FILE=/var/run/rabbitmq/pid"
206 (string-append
207 "RABBITMQ_ENABLED_PLUGINS_FILE="
208 #$data-directory
209 "/enabled_plugins")
210 (string-append
211 "RABBITMQ_MNESIA_BASE="
212 #$data-directory)
213 "RABBITMQ_LOG_BASE=/var/log/rabbitmq")
214 (environ))))
215 (stop #~(make-kill-destructor)))))))
216
217(define rabbitmq-service-type
218 (service-type
219 (name 'rabbitmq)
220 (description "Run the RabbitMQ message broker service.")
221 (extensions (list (service-extension
222 shepherd-root-service-type
223 rabbitmq-shepherd-service)
224 (service-extension activation-service-type
225 rabbitmq-activation)
226 (service-extension account-service-type
227 (const %rabbitmq-accounts))
228 (service-extension
229 profile-service-type
230 (compose list rabbitmq-configuration-rabbitmq))))
231 (default-value (rabbitmq-configuration))))