services: 'references-file' depends on Guile-Gcrypt.
[jackhill/guix/guix.git] / gnu / services / ganeti.scm
CommitLineData
9a622827
MB
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (gnu services ganeti)
20 #:use-module (gnu packages virtualization)
21 #:use-module (gnu services)
22 #:use-module (gnu services mcron)
23 #:use-module (gnu services shepherd)
24 #:use-module (guix gexp)
25 #:use-module (guix records)
26
27 #:use-module (srfi srfi-1)
28 #:use-module (ice-9 match)
29
30 #:export (ganeti-noded-configuration
31 ganeti-noded-configuration?
32 ganeti-noded-configuration-ganeti
33 ganeti-noded-configuration-port
34 ganeti-noded-configuration-address
35 ganeti-noded-configuration-interface
36 ganeti-noded-configuration-max-clients
37 ganeti-noded-configuration-ssl?
38 ganeti-noded-configuration-ssl-key
39 ganeti-noded-configuration-ssl-cert
40 ganeti-noded-configuration-debug?
41 ganeti-noded-service-type
42
43 ganeti-confd-configuration
44 ganeti-confd-configuration?
45 ganeti-confd-configuration-ganeti
46 ganeti-confd-configuration-port
47 ganeti-confd-configuration-address
48 ganeti-confd-configuration-debug
49 ganeti-confd-service-type
50
51 ganeti-wconfd-configuration
52 ganeti-wconfd-configuration?
53 ganeti-wconfd-configuration-ganeti
54 ganeti-wconfd-configuration-no-voting?
55 ganeti-wconfd-configuration-debug?
56 ganeti-wconfd-service-type
57
58 ganeti-luxid-configuration
59 ganeti-luxid-configuration?
60 ganeti-luxid-configuration-ganeti
61 ganeti-luxid-configuration-no-voting?
62 ganeti-luxid-configuration-debug?
63 ganeti-luxid-service-type
64
65 ganeti-rapi-configuration
66 ganeti-rapi-configuration?
67 ganeti-rapi-configuration-ganeti
68 ganeti-rapi-configuration-require-authentication?
69 ganeti-rapi-configuration-port
70 ganeti-rapi-configuration-address
71 ganeti-rapi-configuration-interface
72 ganeti-rapi-configuration-max-clients
73 ganeti-rapi-configuration-ssl?
74 ganeti-rapi-configuration-ssl-key
75 ganeti-rapi-configuration-ssl-cert
76 ganeti-rapi-configuration-debug?
77 ganeti-rapi-service-type
78
79 ganeti-kvmd-configuration
80 ganeti-kvmd-configuration?
81 ganeti-kvmd-configuration-ganeti
82 ganeti-kvmd-configuration-debug?
83 ganeti-kvmd-service-type
84
85 ganeti-mond-configuration
86 ganeti-mond-configuration?
87 ganeti-mond-configuration-ganeti
88 ganeti-mond-configuration-port
89 ganeti-mond-configuration-address
90 ganeti-mond-configuration-debug?
91 ganeti-mond-service-type
92
93 ganeti-metad-configuration
94 ganeti-metad-configuration?
95 ganeti-metad-configuration-ganeti
96 ganeti-metad-configuration-port
97 ganeti-metad-configuration-address
98 ganeti-metad-configuration-debug?
99 ganeti-metad-service-type
100
101 ganeti-watcher-configuration
102 ganeti-watcher-configuration?
103 ganeti-watcher-configuration-ganeti
104 ganeti-watcher-configuration-schedule
105 ganeti-watcher-configuration-rapi-ip
106 ganeti-watcher-configuration-job-age
107 ganeti-watcher-configuration-verify-disks?
108 ganeti-watcher-configuration-debug?
109 ganeti-watcher-service-type
110
111 ganeti-cleaner-configuration
112 ganeti-cleaner-configuration?
113 ganeti-cleaner-configuration-ganeti
114 ganeti-cleaner-configuration-master-schedule
115 ganeti-cleaner-configuration-node-schedule
116 ganeti-cleaner-service-type
117
118 ganeti-os
119 ganeti-os?
120 ganeti-os-name
121 ganeti-os-extension
122 ganeti-os-variants
123
124 ganeti-os-variant
125 ganeti-os-variant?
126 ganeti-os-variant-name
127 ganeti-os-variant-configuration
128
129 %debootstrap-interfaces-hook
130 %debootstrap-grub-hook
131 %default-debootstrap-hooks
132 %default-debootstrap-extra-pkgs
133 debootstrap-configuration
134 debootstrap-configuration?
135 debootstrap-configuration-hooks
136 debootstrap-configuration-proxy
137 debootstrap-configuration-mirror
138 debootstrap-configuration-arch
139 debootstrap-configuration-suite
140 debootstrap-configuration-extra-pkgs
141 debootstrap-configuration-components
142 debootstrap-configuration-generate-cache?
143 debootstrap-configuration-clean-cache
144 debootstrap-configuration-partition-style
145 debootstrap-configuration-partition-alignment
146
147 debootstrap-variant
148 debootstrap-os
149 %default-debootstrap-variants
150
151 guix-variant
152 guix-os
153 %default-guix-variants
154
155 %default-ganeti-os
156
157 ganeti-configuration
158 ganeti-configuration?
159 ganeti-configuration-noded-configuration
160 ganeti-configuration-confd-configuration
161 ganeti-configuration-wconfd-configuration
162 ganeti-configuration-luxid-configuration
163 ganeti-configuration-rapi-configuration
164 ganeti-configuration-kvmd-configuration
165 ganeti-configuration-mond-configuration
166 ganeti-configuration-metad-configuration
167 ganeti-configuration-watcher-configuration
168 ganeti-configuration-cleaner-configuration
169 ganeti-configuration-file-storage-paths
170 ganeti-configuration-os
171 ganeti-service-type))
172
173;;;
174;;; Service definitions for running a Ganeti cluster.
175;;;
176;;; Planned improvements: run daemons (except ganeti-noded) under unprivileged
177;;; user accounts and/or containers. The account names must match the ones
178;;; given to Ganetis configure script. metad needs "setcap" or root in order
179;;; to bind on port 80.
180
181;; Set PATH so the various daemons are able to find the 'ip' executable, LVM,
182;; Ceph, Gluster, etc, without having to add absolute references to everything.
183(define %default-ganeti-environment-variables
184 (list (string-append "PATH="
185 (string-join '("/run/setuid-programs"
186 "/run/current-system/profile/sbin"
187 "/run/current-system/profile/bin")
188 ":"))))
189
190(define-record-type* <ganeti-noded-configuration>
191 ganeti-noded-configuration make-ganeti-noded-configuration
192 ganeti-noded-configuration?
193 (ganeti ganeti-noded-configuration-ganeti ;<package>
194 (default ganeti))
195 (port ganeti-noded-configuration-port ;integer
196 (default 1811))
197 (address ganeti-noded-configuration-address ;string
198 (default "0.0.0.0"))
199 (interface ganeti-noded-configuration-interface ;string | #f
200 (default #f))
201 (max-clients ganeti-noded-configuration-max-clients ;integer
202 (default 20))
203 (ssl? ganeti-noded-configuration-ssl? ;Boolean
204 (default #t))
205 (ssl-key ganeti-noded-configuration-ssl-key ;string
206 (default "/var/lib/ganeti/server.pem"))
207 (ssl-cert ganeti-noded-configuration-ssl-cert ;string
208 (default "/var/lib/ganeti/server.pem"))
209 (debug? ganeti-noded-configuration-debug? ;Boolean
210 (default #f)))
211
212(define ganeti-noded-service
213 (match-lambda
214 (($ <ganeti-noded-configuration> ganeti port address interface max-clients
215 ssl? ssl-key ssl-cert debug?)
216 (list (shepherd-service
217 (documentation "Run the Ganeti node daemon.")
218 (provision '(ganeti-noded))
219 (requirement '(user-processes networking))
220
221 ;; If the daemon stops, it is probably for a good reason;
222 ;; otherwise ganeti-watcher will restart it for us anyway.
223 (respawn? #f)
224
225 (start #~(make-forkexec-constructor
226 (list #$(file-append ganeti "/sbin/ganeti-noded")
227 #$(string-append "--port=" (number->string port))
228 #$(string-append "--bind=" address)
229 #$@(if interface
230 #~((string-append "--interface=" #$interface))
231 #~())
232 #$(string-append "--max-clients="
233 (number->string max-clients))
234 #$@(if ssl?
235 #~((string-append "--ssl-key=" #$ssl-key)
236 (string-append "--ssl-cert=" #$ssl-cert))
237 #~("--no-ssl"))
238 #$@(if debug?
239 #~("--debug")
240 #~()))
241 #:environment-variables
242 '#$%default-ganeti-environment-variables
243 #:pid-file "/var/run/ganeti/ganeti-noded.pid"))
244 (stop #~(make-kill-destructor)))))))
245
246(define ganeti-noded-service-type
247 (service-type (name 'ganeti-noded)
248 (extensions
249 (list (service-extension shepherd-root-service-type
250 ganeti-noded-service)))
251 (default-value (ganeti-noded-configuration))
252 (description
253 "@command{ganeti-noded} is the daemon which is responsible
254for the node functions in the Ganeti system.")))
255
256(define-record-type* <ganeti-confd-configuration>
257 ganeti-confd-configuration make-ganeti-confd-configuration
258 ganeti-confd-configuration?
259 (ganeti ganeti-confd-configuration-ganeti ;<package>
260 (default ganeti))
261 (port ganeti-confd-configuration-port ;integer
262 (default 1814))
263 (address ganeti-confd-configuration-address ;string
264 (default "0.0.0.0"))
265 (debug? ganeti-confd-configuration-debug? ;Boolean
266 (default #f)))
267
268(define ganeti-confd-service
269 (match-lambda
270 (($ <ganeti-confd-configuration> ganeti port address debug?)
271 (list (shepherd-service
272 (documentation "Run the Ganeti confd daemon.")
273 (provision '(ganeti-confd))
274 (requirement '(user-processes networking))
275 (respawn? #f)
276 (start #~(make-forkexec-constructor
277 (list #$(file-append ganeti "/sbin/ganeti-confd")
278 #$(string-append "--port=" (number->string port))
279 #$(string-append "--bind=" address)
280 #$@(if debug?
281 #~("--debug")
282 #~()))
283 #:environment-variables
284 '#$%default-ganeti-environment-variables
285 #:pid-file "/var/run/ganeti/ganeti-confd.pid"))
286 (stop #~(make-kill-destructor)))))))
287
288(define ganeti-confd-service-type
289 (service-type (name 'ganeti-confd)
290 (extensions
291 (list (service-extension shepherd-root-service-type
292 ganeti-confd-service)))
293 (default-value (ganeti-confd-configuration))
294 (description
295 "@command{ganeti-confd} is a daemon used to answer queries
296related to the configuration of a Ganeti cluster.")))
297
298(define-record-type* <ganeti-wconfd-configuration>
299 ganeti-wconfd-configuration make-ganeti-wconfd-configuration
300 ganeti-wconfd-configuration?
301 (ganeti ganeti-wconfd-configuration-ganeti ;<package>
302 (default ganeti))
303 (no-voting? ganeti-wconfd-configuration-no-voting? ;Boolean
304 (default #f))
305 (debug? ganeti-wconfd-configuration-debug? ;Boolean
306 (default #f)))
307
308;; If this file exists, the wconfd daemon will be forcefully started even on
309;; non-master nodes. It is used to accommodate a master-failover scenario.
310(define %wconfd-force-node-hint
311 "/var/lib/ganeti/guix_wconfd_force_node_hint")
312
313(define (wconfd-wrapper ganeti args)
314 ;; Wrapper for the wconfd daemon that looks for the force-node hint.
315 (program-file
316 "wconfd-wrapper"
317 #~(begin
318 (let ((wconfd #$(file-append ganeti "/sbin/ganeti-wconfd"))
319 (force-node? (file-exists? #$%wconfd-force-node-hint)))
320 (if force-node?
321 (execl wconfd wconfd "--force-node" "--no-voting" "--yes-do-it" #$@args)
322 (execl wconfd wconfd #$@args))))))
323
324(define shepherd-wconfd-force-start-action
325 ;; Shepherd action to create the force-node hint and start wconfd.
326 (shepherd-action
327 (name 'force-start)
328 (documentation
329 "Forcefully start wconfd even on non-master nodes (dangerous!).")
330 (procedure #~(lambda _
331 (format #t "Forcefully starting the wconfd daemon...~%")
332 (action 'ganeti-wconfd 'enable)
333 (dynamic-wind
334 (lambda ()
335 (false-if-exception
336 (call-with-output-file #$%wconfd-force-node-hint
337 (lambda (port)
338 (const #t)))))
339 (lambda ()
340 (action 'ganeti-wconfd 'restart))
341 (lambda ()
342 (delete-file #$%wconfd-force-node-hint)))
343 #t))))
344
345(define ganeti-wconfd-service
346 (match-lambda
347 (($ <ganeti-wconfd-configuration> ganeti no-voting? debug?)
348 (list (shepherd-service
349 (documentation "Run the Ganeti wconfd daemon.")
350 (provision '(ganeti-wconfd))
351 (requirement '(user-processes))
352
353 ;; Shepherd action to support a master-failover scenario. It is
354 ;; automatically invoked during 'gnt-cluster master-failover' (see
355 ;; related Ganeti patch) and not intended for interactive use.
356 (actions (list shepherd-wconfd-force-start-action))
357
358 ;; wconfd will disable itself when not running on the master
359 ;; node. Don't attempt to restart it.
360 (respawn? #f)
361
362 (start
363 #~(make-forkexec-constructor
364 (list #$(wconfd-wrapper ganeti
365 (append
366 (if no-voting?
367 '("--no-voting" "--yes-do-it")
368 '())
369 (if debug?
370 '("--debug")
371 '()))))
372 #:environment-variables
373 '#$%default-ganeti-environment-variables
374 #:pid-file "/var/run/ganeti/ganeti-wconfd.pid"))
375 (stop #~(make-kill-destructor)))))))
376
377(define ganeti-wconfd-service-type
378 (service-type (name 'ganeti-wconfd)
379 (extensions
380 (list (service-extension shepherd-root-service-type
381 ganeti-wconfd-service)))
382 (default-value (ganeti-wconfd-configuration))
383 (description
384 "@command{ganeti-wconfd} is the daemon that has authoritative
385knowledge about the configuration and is the only entity that can accept changes
386to it. All jobs that need to modify the configuration will do so by sending
387appropriate requests to this daemon.")))
388
389(define-record-type* <ganeti-luxid-configuration>
390 ganeti-luxid-configuration make-ganeti-luxid-configuration
391 ganeti-luxid-configuration?
392 (ganeti ganeti-luxid-configuration-ganeti ;<package>
393 (default ganeti))
394 (no-voting? ganeti-luxid-configuration-no-voting? ;Boolean
395 (default #f))
396 (debug? ganeti-luxid-configuration-debug? ;Boolean
397 (default #f)))
398
399(define ganeti-luxid-service
400 (match-lambda
401 (($ <ganeti-luxid-configuration> ganeti no-voting? debug?)
402 (list (shepherd-service
403 (documentation "Run the Ganeti LUXI daemon.")
404 (provision '(ganeti-luxid))
405 (requirement '(user-processes))
406
407 ;; This service will automatically disable itself when not
408 ;; running on the master node. Don't attempt to restart it.
409 (respawn? #f)
410
411 (start #~(make-forkexec-constructor
412 (list #$(file-append ganeti "/sbin/ganeti-luxid")
413 #$@(if no-voting?
414 #~("--no-voting" "--yes-do-it")
415 #~())
416 #$@(if debug?
417 #~("--debug")
418 #~()))
419 #:environment-variables
420 '#$%default-ganeti-environment-variables
421 #:pid-file "/var/run/ganeti/ganeti-luxid.pid"))
422 (stop #~(make-kill-destructor)))))))
423
424(define ganeti-luxid-service-type
425 (service-type (name 'ganeti-luxid)
426 (extensions
427 (list (service-extension shepherd-root-service-type
428 ganeti-luxid-service)))
429 (default-value (ganeti-luxid-configuration))
430 (description
431 "@command{ganeti-luxid} is a daemon used to answer queries
432related to the configuration and the current live state of a Ganeti cluster.
7db4dc60 433Additionally, it is the authoritative daemon for the Ganeti job queue. Jobs can
9a622827
MB
434be submitted via this daemon and it schedules and starts them.")))
435
436(define-record-type* <ganeti-rapi-configuration>
437 ganeti-rapi-configuration make-ganeti-rapi-configuration
438 ganeti-rapi-configuration?
439 (ganeti ganeti-rapi-configuration-ganeti ;<package>
440 (default ganeti))
441 (require-authentication?
442 ganeti-rapi-configuration-require-authentication? ;Boolean
443 (default #f))
444 (port ganeti-rapi-configuration-port ;integer
445 (default 5080))
446 (address ganeti-rapi-configuration-address ;string
447 (default "0.0.0.0"))
448 (interface ganeti-rapi-configuration-interface ;string | #f
449 (default #f))
450 (max-clients ganeti-rapi-configuration-max-clients ;integer
451 (default 20))
452 (ssl? ganeti-rapi-configuration-ssl? ;Boolean
41daf128 453 (default #t))
9a622827
MB
454 (ssl-key ganeti-rapi-configuration-ssl-key ;string
455 (default "/var/lib/ganeti/server.pem"))
456 (ssl-cert ganeti-rapi-configuration-ssl-cert ;string
457 (default "/var/lib/ganeti/server.pem"))
458 (debug? ganeti-rapi-configuration-debug? ;Boolean
459 (default #f)))
460
461(define ganeti-rapi-service
462 (match-lambda
463 (($ <ganeti-rapi-configuration> ganeti require-authentication? port address
464 interface max-clients ssl? ssl-key ssl-cert
465 debug?)
466 (list (shepherd-service
467 (documentation "Run the Ganeti RAPI daemon.")
468 (provision '(ganeti-rapi))
469 (requirement '(user-processes networking))
470
471 ;; This service will automatically disable itself when not
472 ;; running on the master node. Don't attempt to restart it.
473 (respawn? #f)
474
475 (start #~(make-forkexec-constructor
476 (list #$(file-append ganeti "/sbin/ganeti-rapi")
477 #$@(if require-authentication?
478 #~("--require-authentication")
479 #~())
480 #$(string-append "--port=" (number->string port))
481 #$(string-append "--bind=" address)
482 #$@(if interface
483 #~((string-append "--interface=" #$interface))
484 #~())
485 #$(string-append "--max-clients="
486 (number->string max-clients))
487 #$@(if ssl?
488 #~((string-append "--ssl-key=" #$ssl-key)
489 (string-append "--ssl-cert=" #$ssl-cert))
490 #~("--no-ssl"))
491 #$@(if debug?
492 #~("--debug")
493 #~()))
494 #:environment-variables
495 '#$%default-ganeti-environment-variables
496 #:pid-file "/var/run/ganeti/ganeti-rapi.pid"))
497 (stop #~(make-kill-destructor)))))))
498
499(define ganeti-rapi-service-type
500 (service-type (name 'ganeti-rapi)
501 (extensions
502 (list (service-extension shepherd-root-service-type
503 ganeti-rapi-service)))
504 (default-value (ganeti-rapi-configuration))
505 (description
506 "@command{ganeti-rapi} is the daemon providing a remote API
507for Ganeti clusters.")))
508
509(define-record-type* <ganeti-kvmd-configuration>
510 ganeti-kvmd-configuration make-ganeti-kvmd-configuration
511 ganeti-kvmd-configuration?
512 (ganeti ganeti-kvmd-configuration-ganeti ;<package>
513 (default ganeti))
514 (debug? ganeti-kvmd-configuration-debug? ;Boolean
515 (default #f)))
516
517(define ganeti-kvmd-service
518 (match-lambda
519 (($ <ganeti-kvmd-configuration> ganeti debug?)
520 (list (shepherd-service
521 (documentation "Run the Ganeti KVM daemon.")
522 (provision '(ganeti-kvmd))
523 (requirement '(user-processes))
524
525 ;; This service will automatically disable itself when not
526 ;; needed. Don't attempt to restart it.
527 (respawn? #f)
528
529 (start #~(make-forkexec-constructor
530 (list #$(file-append ganeti "/sbin/ganeti-kvmd")
531 #$@(if debug?
532 #~("--debug")
533 #~()))
534 #:environment-variables
535 '#$%default-ganeti-environment-variables
536 #:pid-file "/var/run/ganeti/ganeti-kvmd.pid"))
537 (stop #~(make-kill-destructor)))))))
538
539(define ganeti-kvmd-service-type
540 (service-type (name 'ganeti-kvmd)
541 (extensions
542 (list (service-extension shepherd-root-service-type
543 ganeti-kvmd-service)))
544 (default-value (ganeti-kvmd-configuration))
545 (description
546 "@command{ganeti-kvmd} is responsible for determining whether
547a given KVM instance was shutdown by an administrator or a user.
548
549The KVM daemon monitors, using @code{inotify}, KVM instances through their QMP
550sockets, which are provided by KVM. Using the QMP sockets, the KVM daemon
551listens for particular shutdown, powerdown, and stop events which will determine
552if a given instance was shutdown by the user or Ganeti, and this result is
2e832d4b 553communicated to Ganeti via a special file in the file system.")))
9a622827
MB
554
555(define-record-type* <ganeti-mond-configuration>
556 ganeti-mond-configuration make-ganeti-mond-configuration
557 ganeti-mond-configuration?
558 (ganeti ganeti-mond-configuration-ganeti ;<package>
559 (default ganeti))
560 (port ganeti-mond-configuration-port ;integer
561 (default 1815))
562 (address ganeti-mond-configuration-address ;string
563 (default "0.0.0.0"))
564 (debug? ganeti-mond-configuration-debug? ;Boolean
565 (default #f)))
566
567(define ganeti-mond-service
568 (match-lambda
569 (($ <ganeti-mond-configuration> ganeti port address debug?)
570 (list (shepherd-service
571 (documentation "Run the Ganeti monitoring daemon.")
572 (provision '(ganeti-mond))
573 (requirement '(user-processes networking))
574 (respawn? #f)
575 (start #~(make-forkexec-constructor
576 (list #$(file-append ganeti "/sbin/ganeti-mond")
577 #$(string-append "--port=" (number->string port))
578 #$(string-append "--bind=" address)
579 #$@(if debug?
580 #~("--debug")
581 #~()))
582 #:pid-file "/var/run/ganeti/ganeti-mond.pid"))
583 (stop #~(make-kill-destructor)))))))
584
585(define ganeti-mond-service-type
586 (service-type (name 'ganeti-mond)
587 (extensions
588 (list (service-extension shepherd-root-service-type
589 ganeti-mond-service)))
590 (default-value (ganeti-mond-configuration))
591 (description
592 "@command{ganeti-mond} is a daemon providing monitoring
593functionality. It is responsible for running the data collectors and to
594provide the collected information through a HTTP interface.")))
595
596(define-record-type* <ganeti-metad-configuration>
597 ganeti-metad-configuration make-ganeti-metad-configuration
598 ganeti-metad-configuration?
599 (ganeti ganeti-metad-configuration-ganeti ;<package>
600 (default ganeti))
601 (port ganeti-metad-configuration-port ;integer
602 (default 80))
603 (address ganeti-metad-configuration-address ;string | #f
604 (default #f))
605 (debug? ganeti-metad-configuration-debug? ;Boolean
606 (default #f)))
607
608(define ganeti-metad-service
609 (match-lambda
610 (($ <ganeti-metad-configuration> ganeti port address debug?)
611 (list (shepherd-service
612 (documentation "Run the Ganeti metadata daemon.")
613 (provision '(ganeti-metad))
614 (requirement '(user-processes networking))
615 (respawn? #f)
616 (start #~(make-forkexec-constructor
617 (list #$(file-append ganeti "/sbin/ganeti-metad")
618 #$(string-append "--port=" (number->string port))
619 #$@(if address
620 #~((string-append "--bind=" #$address))
621 #~())
622 #$@(if debug?
623 #~("--debug")
624 #~()))
625 #:pid-file "/var/run/ganeti/ganeti-metad.pid"))
626 (stop #~(make-kill-destructor)))))))
627
628(define ganeti-metad-service-type
629 (service-type (name 'ganeti-metad)
630 (extensions
631 (list (service-extension shepherd-root-service-type
632 ganeti-metad-service)))
633 (default-value (ganeti-metad-configuration))
634 (description
635 "@command{ganeti-metad} is a daemon that can be used to pass
636information to OS install scripts or instances.")))
637
638(define-record-type* <ganeti-watcher-configuration>
639 ganeti-watcher-configuration make-ganeti-watcher-configuration
640 ganeti-watcher-configuration?
641 (ganeti ganeti-watcher-configuration-ganeti ;<package>
642 (default ganeti))
643 (schedule ganeti-watcher-configuration-schedule ;list | string
644 (default '(next-second-from
645 ;; Run every five minutes.
646 (next-minute (range 0 60 5)))))
647 (rapi-ip ganeti-watcher-configuration-rapi-ip ;#f | string
648 (default #f))
649 (job-age ganeti-watcher-configuration-job-age ;integer
650 (default (* 6 3600)))
651 (verify-disks? ganeti-watcher-configuration-verify-disks? ;Boolean
652 (default #t))
653 (debug? ganeti-watcher-configuration-debug? ;Boolean
654 (default #f)))
655
656(define ganeti-watcher-command
657 (match-lambda
658 (($ <ganeti-watcher-configuration> ganeti _ rapi-ip job-age verify-disks?
659 debug?)
660 #~(lambda ()
661 (system* #$(file-append ganeti "/sbin/ganeti-watcher")
662 #$@(if rapi-ip
938f3190 663 #~((string-append "--rapi-ip=" #$rapi-ip))
9a622827
MB
664 #~())
665 #$(string-append "--job-age=" (number->string job-age))
666 #$@(if verify-disks?
667 #~()
668 #~("--no-verify-disks"))
669 #$@(if debug?
670 #~("--debug")
671 #~()))))))
672
673(define (ganeti-watcher-jobs config)
674 (match config
675 (($ <ganeti-watcher-configuration> _ schedule)
676 (list
677 #~(job #$@(match schedule
678 ((? string?)
679 #~(#$schedule))
680 ((? list?)
681 #~('#$schedule)))
682 #$(ganeti-watcher-command config))))))
683
684(define ganeti-watcher-service-type
685 (service-type (name 'ganeti-watcher)
686 (extensions
687 (list (service-extension mcron-service-type
688 ganeti-watcher-jobs)))
689 (default-value (ganeti-watcher-configuration))
690 (description
691 "@command{ganeti-watcher} is a periodically run script that
692performs a number of maintenance actions on the cluster. It will automatically
693restart instances that are marked as ERROR_down, i.e., instances that should be
694running, but are not; and it will also try to repair DRBD links in case a
695secondary node has rebooted. In addition it is responsible for archiving old
696cluster jobs, and it will restart any down Ganeti daemons that are appropriate
697for the current node. If the cluster parameter @code{maintain_node_health} is
698enabled, the watcher will also shutdown instances and DRBD devices if the node
699is declared offline by known master candidates.")))
700
701(define-record-type* <ganeti-cleaner-configuration>
702 ganeti-cleaner-configuration make-ganeti-cleaner-configuration
703 ganeti-cleaner-configuration?
704 (ganeti ganeti-cleaner-configuration-ganeti ;<package>
705 (default ganeti))
706 (master-schedule ganeti-cleaner-configuration-master-schedule ;list | string
707 ;; Run the master cleaner at 01:45 every day.
708 (default "45 1 * * *"))
709 (node-schedule ganeti-cleaner-configuration-node-schedule ;list | string
710 ;; Run the node cleaner at 02:45 every day.
711 (default "45 2 * * *")))
712
713(define ganeti-cleaner-jobs
714 (match-lambda
715 (($ <ganeti-cleaner-configuration> ganeti master-schedule node-schedule)
716 (list
717 #~(job #$@(match master-schedule
718 ((? string?)
719 #~(#$master-schedule))
720 ((? list?)
721 #~('#$master-schedule)))
722 (lambda ()
723 (system* #$(file-append ganeti "/sbin/ganeti-cleaner")
724 "master")))
725 #~(job #$@(match node-schedule
726 ((? string?)
727 #~(#$node-schedule))
728 ((? list?)
729 #~('#$node-schedule)))
730 (lambda ()
731 (system* #$(file-append ganeti "/sbin/ganeti-cleaner")
732 "node")))))))
733
734(define ganeti-cleaner-service-type
735 (service-type (name 'ganeti-cleaner)
736 (extensions
737 (list (service-extension mcron-service-type
738 ganeti-cleaner-jobs)))
739 (default-value (ganeti-cleaner-configuration))
740 (description
741 "@command{ganeti-cleaner} is a script that removes old files
742from the cluster. When called with @code{node} as argument it removes expired
743X509 certificates and keys from @file{/var/run/ganeti/crypto}, as well as
744outdated @command{ganeti-watcher} information.
745
746When called with @code{master} as argument, it instead removes files older
747than 21 days from @file{/var/lib/ganeti/queue/archive}.")))
748
749(define-record-type* <ganeti-configuration>
750 ganeti-configuration make-ganeti-configuration
751 ganeti-configuration?
752 (ganeti ganeti-configuration-ganeti
753 (default ganeti))
754 (noded-configuration ganeti-configuration-noded-configuration
755 (default (ganeti-noded-configuration)))
756 (confd-configuration ganeti-configuration-confd-configuration
757 (default (ganeti-confd-configuration)))
758 (wconfd-configuration ganeti-configuration-wconfd-configuration
759 (default (ganeti-wconfd-configuration)))
760 (luxid-configuration ganeti-configuration-luxid-configuration
761 (default (ganeti-luxid-configuration)))
762 (rapi-configuration ganeti-configuration-rapi-configuration
763 (default (ganeti-rapi-configuration)))
764 (kvmd-configuration ganeti-configuration-kvmd-configuration
765 (default (ganeti-kvmd-configuration)))
766 (mond-configuration ganeti-configuration-mond-configuration
767 (default (ganeti-mond-configuration)))
768 (metad-configuration ganeti-configuration-metad-configuration
769 (default (ganeti-metad-configuration)))
770 (watcher-configuration ganeti-configuration-watcher-configuration
771 (default (ganeti-watcher-configuration)))
772 (cleaner-configuration ganeti-configuration-cleaner-configuration
773 (default (ganeti-cleaner-configuration)))
774 (file-storage-paths ganeti-configuration-file-storage-paths ;list of strings | gexp
775 (default '()))
776 (os ganeti-configuration-os ;list of <ganeti-os>
777 (default '())))
778
779(define (ganeti-activation config)
780 (with-imported-modules '((guix build utils))
781 #~(begin
782 (use-modules (guix build utils))
783 (for-each mkdir-p
784 '("/var/log/ganeti"
785 "/var/log/ganeti/kvm"
786 "/var/log/ganeti/os"
787 "/var/lib/ganeti/rapi"
788 "/var/lib/ganeti/queue"
789 "/var/lib/ganeti/queue/archive"
790 "/var/run/ganeti/bdev-cache"
791 "/var/run/ganeti/crypto"
792 "/var/run/ganeti/socket"
793 "/var/run/ganeti/instance-disks"
794 "/var/run/ganeti/instance-reason"
795 "/var/run/ganeti/livelocks")))))
796
797(define ganeti-shepherd-services
798 (match-lambda
799 (($ <ganeti-configuration> _ noded confd wconfd luxid rapi kvmd mond metad)
800 (append (ganeti-noded-service noded)
801 (ganeti-confd-service confd)
802 (ganeti-wconfd-service wconfd)
803 (ganeti-luxid-service luxid)
804 (ganeti-rapi-service rapi)
805 (ganeti-kvmd-service kvmd)
806 (ganeti-mond-service mond)
807 (ganeti-metad-service metad)))))
808
809(define ganeti-mcron-jobs
810 (match-lambda
811 (($ <ganeti-configuration> _ _ _ _ _ _ _ _ _ watcher cleaner)
812 (append (ganeti-watcher-jobs watcher)
813 (ganeti-cleaner-jobs cleaner)))))
814
815(define-record-type* <ganeti-os>
816 ganeti-os make-ganeti-os ganeti-os?
817 (name ganeti-os-name) ;string
818 (extension ganeti-os-extension) ;string
819 (variants ganeti-os-variants ;list of <ganeti-os-variant>
820 (default '())))
821
822(define-record-type* <ganeti-os-variant>
823 ganeti-os-variant make-ganeti-os-variant ganeti-os-variant?
824 (name ganeti-os-variant-name) ;string
825 (configuration ganeti-os-variant-configuration)) ;<file-like>
826
827(define %debootstrap-interfaces-hook
828 (file-append ganeti-instance-debootstrap
829 "/share/doc/ganeti-instance-debootstrap/examples/interfaces"))
830
831;; The GRUB hook shipped with instance-debootstrap does not work with GRUB2.
832;; For convenience, provide one that work with modern Debians here.
833;; Note: it would be neat to reuse Guix' bootloader infrastructure instead.
834(define %debootstrap-grub-hook
835 (plain-file "grub"
836 "#!/usr/bin/env bash
837CLEANUP=( )
838cleanup() {
839 if [ ${#CLEANUP[*]} -gt 0 ]; then
840 LAST_ELEMENT=$((${#CLEANUP[*]}-1))
841 REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
842 for i in $REVERSE_INDEXES; do
843 ${CLEANUP[$i]}
844 done
845 fi
846}
847
848trap cleanup EXIT
849
850mount -t proc proc $TARGET/proc
851CLEANUP+=(\"umount $TARGET/proc\")
852mount -t sysfs sysfs $TARGET/sys
853CLEANUP+=(\"umount $TARGET/sys\")
854mount -o bind /dev $TARGET/dev
855CLEANUP+=(\"umount $TARGET/dev\")
856
857echo '
858GRUB_TIMEOUT_STYLE=menu
859GRUB_CMDLINE_LINUX_DEFAULT=\"console=ttyS0,115200 net.ifnames=0\"
860GRUB_TERMINAL=\"serial\"
861GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"
862' >> $TARGET/etc/default/grub
863
864# This PATH is propagated into the chroot and necessary to make grub-install
865# and related commands visible.
866export PATH=\"/usr/sbin:/usr/bin:/sbin:/bin:$PATH\"
867
868chroot \"$TARGET\" grub-install $BLOCKDEV
869chroot \"$TARGET\" update-grub
870
871cleanup
872trap - EXIT
873"))
874
875(define %default-debootstrap-hooks
876 `((10-interfaces . ,%debootstrap-interfaces-hook)
877 (90-grub . ,%debootstrap-grub-hook)))
878
879(define %default-debootstrap-extra-pkgs
880 ;; Packages suitable for a fully virtualized KVM guest.
881 '("acpi-support-base" "udev" "linux-image-amd64" "openssh-server"
882 "locales-all" "grub-pc"))
883
884(define-record-type* <debootstrap-configuration>
885 debootstrap-configuration make-debootstrap-configuration
886 debootstrap-configuration?
887 (hooks debootstrap-configuration-hooks ;#f | gexp | '((name . gexp))
888 (default %default-debootstrap-hooks))
889 (proxy debootstrap-configuration-proxy (default #f)) ;#f | string
890 (mirror debootstrap-configuration-mirror ;#f | string
891 (default #f))
892 (arch debootstrap-configuration-arch (default #f)) ;#f | string
893 (suite debootstrap-configuration-suite ;#f | string
894 (default "stable"))
895 (extra-pkgs debootstrap-configuration-extra-pkgs ;list of strings
896 (default %default-debootstrap-extra-pkgs))
897 (components debootstrap-configuration-components ;list of strings
898 (default '()))
899 (generate-cache? debootstrap-configuration-generate-cache? ;Boolean
900 (default #t))
901 (clean-cache debootstrap-configuration-clean-cache ;#f | integer
902 (default 14))
903 (partition-style debootstrap-configuration-partition-style ;#f | symbol | string
904 (default 'msdos))
905 (partition-alignment debootstrap-configuration-partition-alignment ;#f | integer
906 (default 2048)))
907
908(define (hooks->directory hooks)
909 (match hooks
910 ((? file-like?)
911 hooks)
912 ((? list?)
913 (let ((names (map car hooks))
914 (files (map cdr hooks)))
915 (with-imported-modules '((guix build utils))
916 (computed-file "hooks-union"
917 #~(begin
918 (use-modules (guix build utils)
919 (ice-9 match))
920 (mkdir-p #$output)
921 (with-directory-excursion #$output
922 (for-each (match-lambda
923 ((name hook)
924 (let ((file-name (string-append
925 #$output "/"
926 (symbol->string name))))
927 ;; Copy to the destination to ensure
928 ;; the file is executable.
929 (copy-file hook file-name)
930 (chmod file-name #o555))))
931 '#$(zip names files))))))))
932 (_ #f)))
933
934(define-gexp-compiler (debootstrap-configuration-compiler
935 (file <debootstrap-configuration>) system target)
936 (match file
937 (($ <debootstrap-configuration> hooks proxy mirror arch suite extra-pkgs
938 components generate-cache? clean-cache
939 partition-style partition-alignment)
940 (let ((customize-dir (hooks->directory hooks)))
941 (gexp->derivation
942 "debootstrap-variant"
943 #~(call-with-output-file (ungexp output "out")
944 (lambda (port)
945 (display
946 (string-append
947 (ungexp-splicing
948 `(,@(if proxy
949 `("PROXY=" ,proxy "\n")
950 '())
951 ,@(if mirror
952 `("MIRROR=" ,mirror "\n")
953 '())
954 ,@(if arch
955 `("ARCH=" ,arch "\n")
956 '())
957 ,@(if suite
958 `("SUITE=" ,suite "\n")
959 '())
960 ,@(if (not (null? extra-pkgs))
961 `("EXTRA_PKGS=" ,(string-join extra-pkgs ",") "\n")
962 '())
963 ,@(if (not (null? components))
964 `("COMPONENTS=" ,(string-join components ",") "\n")
965 '())
966 ,@(if customize-dir
967 `("CUSTOMIZE_DIR=" ,customize-dir "\n")
968 '())
969 ,@(if generate-cache?
970 '("GENERATE_CACHE=yes\n")
971 '("GENERATE_CACHE=no\n"))
972 ,@(if clean-cache
973 `("CLEAN_CACHE=" ,(number->string clean-cache) "\n")
974 '())
975 ,@(if partition-style
976 (if (symbol? partition-style)
977 `("PARTITION_STYLE="
978 ,(symbol->string partition-style) "\n")
979 `("PARTITION_STYLE=" ,partition-style "\n"))
980 '())
981 ,@(if partition-alignment
982 `("PARTITION_ALIGNMENT="
983 ,(number->string partition-alignment) "\n")
984 '()))))
985 port)))
986 #:local-build? #t)))))
987
988(define (ganeti-os->directory os)
989 "Return the derivation to build the configuration directory to be installed
990in /etc/ganeti/instance-$os for OS."
991 (let* ((name (ganeti-os-name os))
992 (extension (ganeti-os-extension os))
993 (variants (ganeti-os-variants os))
994 (names (map ganeti-os-variant-name variants))
995 (configs (map ganeti-os-variant-configuration variants)))
996 (with-imported-modules '((guix build utils))
997 (define builder
998 #~(begin
999 (use-modules (guix build utils)
1000 (ice-9 format)
1001 (ice-9 match)
1002 (srfi srfi-1))
1003 (mkdir-p #$output)
1004 (unless (null? '#$names)
1005 (let ((variants-dir (string-append #$output "/variants")))
1006 (mkdir-p variants-dir)
1007 (call-with-output-file (string-append variants-dir "/variants.list")
1008 (lambda (port)
1009 (format port "~a~%"
1010 (string-join '#$names "\n"))))
1011 (for-each (match-lambda
1012 ((name file)
1013 (symlink file
1014 (string-append variants-dir "/" name
1015 #$extension))))
1016
1017 '#$(zip names configs))))))
1018
1019 (computed-file (string-append name "-os") builder))))
1020
1021(define (ganeti-directory file-storage-file os)
1022 (let ((dirs (map ganeti-os->directory os))
1023 (names (map ganeti-os-name os)))
1024 (define builder
1025 #~(begin
1026 (use-modules (ice-9 match))
1027 (mkdir #$output)
1028 (when #$file-storage-file
1029 (symlink #$file-storage-file
1030 (string-append #$output "/file-storage-paths")))
1031 (for-each (match-lambda
1032 ((name dest)
1033 (symlink dest
1034 (string-append #$output "/instance-" name))))
1035 '#$(zip names dirs))))
1036 (computed-file "etc-ganeti" builder)))
1037
1038(define (file-storage-file paths)
1039 (match paths
1040 ((? null?) #f)
1041 ((? list?) (plain-file
1042 "file-storage-paths"
1043 (string-join paths "\n")))
1044 (_ paths)))
1045
1046(define (ganeti-etc-service config)
1047 (list `("ganeti" ,(ganeti-directory
1048 (file-storage-file
1049 (ganeti-configuration-file-storage-paths config))
1050 (ganeti-configuration-os config)))))
1051
1052(define (debootstrap-os variants)
1053 (ganeti-os
1054 (name "debootstrap")
1055 (extension ".conf")
1056 (variants variants)))
1057
1058(define (debootstrap-variant name configuration)
1059 (ganeti-os-variant
1060 (name name)
1061 (configuration configuration)))
1062
1063(define %default-debootstrap-variants
1064 (list (debootstrap-variant
1065 "default"
1066 (debootstrap-configuration))))
1067
1068(define (guix-os variants)
1069 (ganeti-os
1070 (name "guix")
1071 (extension ".scm")
1072 (variants variants)))
1073
1074(define (guix-variant name configuration)
1075 (ganeti-os-variant
1076 (name name)
1077 (configuration configuration)))
1078
1079(define %default-guix-variants
1080 (list (guix-variant
1081 "default"
1082 (file-append ganeti-instance-guix
1083 "/share/doc/ganeti-instance-guix/examples/dynamic.scm"))))
1084
1085;; The OS configurations usually come with a default OS. To make them work
1086;; out of the box, follow suit.
1087(define %default-ganeti-os
1088 (list (debootstrap-os %default-debootstrap-variants)
1089 (guix-os %default-guix-variants)))
1090
1091(define ganeti-service-type
1092 (service-type (name 'ganeti)
1093 (extensions
1094 (list (service-extension activation-service-type
1095 ganeti-activation)
1096 (service-extension shepherd-root-service-type
1097 ganeti-shepherd-services)
1098 (service-extension etc-service-type
1099 ganeti-etc-service)
1100 (service-extension profile-service-type
1101 (compose list ganeti-configuration-ganeti))
1102 (service-extension mcron-service-type
1103 ganeti-mcron-jobs)))
1104 (default-value (ganeti-configuration (os %default-ganeti-os)))
1105 (description
1106 "Ganeti is a family of services that are designed to run
1107on a fleet of machines and facilitate deployment and maintenance of virtual
1108servers (@dfn{instances}). It can migrate instances between nodes, automatically
1109restart failed instances, evacuate nodes, and much more.")))