ganeti.scm 47 KB

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