Commit | Line | Data |
---|---|---|
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 | |
254 | for 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 | |
296 | related 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 | |
385 | knowledge about the configuration and is the only entity that can accept changes | |
386 | to it. All jobs that need to modify the configuration will do so by sending | |
387 | appropriate 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 | |
432 | related to the configuration and the current live state of a Ganeti cluster. | |
433 | Additionally, it is the autorative daemon for the Ganeti job queue. Jobs can | |
434 | be 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 | |
507 | for 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 | |
547 | a given KVM instance was shutdown by an administrator or a user. | |
548 | ||
549 | The KVM daemon monitors, using @code{inotify}, KVM instances through their QMP | |
550 | sockets, which are provided by KVM. Using the QMP sockets, the KVM daemon | |
551 | listens for particular shutdown, powerdown, and stop events which will determine | |
552 | if a given instance was shutdown by the user or Ganeti, and this result is | |
2e832d4b | 553 | communicated 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 | |
593 | functionality. It is responsible for running the data collectors and to | |
594 | provide 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 | |
636 | information 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 | |
692 | performs a number of maintenance actions on the cluster. It will automatically | |
693 | restart instances that are marked as ERROR_down, i.e., instances that should be | |
694 | running, but are not; and it will also try to repair DRBD links in case a | |
695 | secondary node has rebooted. In addition it is responsible for archiving old | |
696 | cluster jobs, and it will restart any down Ganeti daemons that are appropriate | |
697 | for the current node. If the cluster parameter @code{maintain_node_health} is | |
698 | enabled, the watcher will also shutdown instances and DRBD devices if the node | |
699 | is 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 | |
742 | from the cluster. When called with @code{node} as argument it removes expired | |
743 | X509 certificates and keys from @file{/var/run/ganeti/crypto}, as well as | |
744 | outdated @command{ganeti-watcher} information. | |
745 | ||
746 | When called with @code{master} as argument, it instead removes files older | |
747 | than 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 | |
837 | CLEANUP=( ) | |
838 | cleanup() { | |
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 | ||
848 | trap cleanup EXIT | |
849 | ||
850 | mount -t proc proc $TARGET/proc | |
851 | CLEANUP+=(\"umount $TARGET/proc\") | |
852 | mount -t sysfs sysfs $TARGET/sys | |
853 | CLEANUP+=(\"umount $TARGET/sys\") | |
854 | mount -o bind /dev $TARGET/dev | |
855 | CLEANUP+=(\"umount $TARGET/dev\") | |
856 | ||
857 | echo ' | |
858 | GRUB_TIMEOUT_STYLE=menu | |
859 | GRUB_CMDLINE_LINUX_DEFAULT=\"console=ttyS0,115200 net.ifnames=0\" | |
860 | GRUB_TERMINAL=\"serial\" | |
861 | GRUB_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. | |
866 | export PATH=\"/usr/sbin:/usr/bin:/sbin:/bin:$PATH\" | |
867 | ||
868 | chroot \"$TARGET\" grub-install $BLOCKDEV | |
869 | chroot \"$TARGET\" update-grub | |
870 | ||
871 | cleanup | |
872 | trap - 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 | |
990 | in /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 | |
1107 | on a fleet of machines and facilitate deployment and maintenance of virtual | |
1108 | servers (@dfn{instances}). It can migrate instances between nodes, automatically | |
1109 | restart failed instances, evacuate nodes, and much more."))) |