ganeti.scm 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  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 ;<package>
  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 ;<package>
  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 ;<package>
  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 ;<package>
  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 autorative 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 ;<package>
  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 ;<package>
  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 ;<package>
  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 ;<package>
  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. (respawn? #f)
  557. (start #~(make-forkexec-constructor
  558. (list #$(file-append ganeti "/sbin/ganeti-metad")
  559. #$(string-append "--port=" (number->string port))
  560. #$@(if address
  561. #~((string-append "--bind=" #$address))
  562. #~())
  563. #$@(if debug?
  564. #~("--debug")
  565. #~()))
  566. #:pid-file "/var/run/ganeti/ganeti-metad.pid"))
  567. (stop #~(make-kill-destructor)))))))
  568. (define ganeti-metad-service-type
  569. (service-type (name 'ganeti-metad)
  570. (extensions
  571. (list (service-extension shepherd-root-service-type
  572. ganeti-metad-service)))
  573. (default-value (ganeti-metad-configuration))
  574. (description
  575. "@command{ganeti-metad} is a daemon that can be used to pass
  576. information to OS install scripts or instances.")))
  577. (define-record-type* <ganeti-watcher-configuration>
  578. ganeti-watcher-configuration make-ganeti-watcher-configuration
  579. ganeti-watcher-configuration?
  580. (ganeti ganeti-watcher-configuration-ganeti ;<package>
  581. (default ganeti))
  582. (schedule ganeti-watcher-configuration-schedule ;list | string
  583. (default '(next-second-from
  584. ;; Run every five minutes.
  585. (next-minute (range 0 60 5)))))
  586. (rapi-ip ganeti-watcher-configuration-rapi-ip ;#f | string
  587. (default #f))
  588. (job-age ganeti-watcher-configuration-job-age ;integer
  589. (default (* 6 3600)))
  590. (verify-disks? ganeti-watcher-configuration-verify-disks? ;Boolean
  591. (default #t))
  592. (debug? ganeti-watcher-configuration-debug? ;Boolean
  593. (default #f)))
  594. (define ganeti-watcher-command
  595. (match-lambda
  596. (($ <ganeti-watcher-configuration> ganeti _ rapi-ip job-age verify-disks?
  597. debug?)
  598. #~(lambda ()
  599. (system* #$(file-append ganeti "/sbin/ganeti-watcher")
  600. #$@(if rapi-ip
  601. #~((string-append "--rapi-ip=" #$rapi-ip))
  602. #~())
  603. #$(string-append "--job-age=" (number->string job-age))
  604. #$@(if verify-disks?
  605. #~()
  606. #~("--no-verify-disks"))
  607. #$@(if debug?
  608. #~("--debug")
  609. #~()))))))
  610. (define (ganeti-watcher-jobs config)
  611. (match config
  612. (($ <ganeti-watcher-configuration> _ schedule)
  613. (list
  614. #~(job #$@(match schedule
  615. ((? string?)
  616. #~(#$schedule))
  617. ((? list?)
  618. #~('#$schedule)))
  619. #$(ganeti-watcher-command config))))))
  620. (define ganeti-watcher-service-type
  621. (service-type (name 'ganeti-watcher)
  622. (extensions
  623. (list (service-extension mcron-service-type
  624. ganeti-watcher-jobs)))
  625. (default-value (ganeti-watcher-configuration))
  626. (description
  627. "@command{ganeti-watcher} is a periodically run script that
  628. performs a number of maintenance actions on the cluster. It will automatically
  629. restart instances that are marked as ERROR_down, i.e., instances that should be
  630. running, but are not; and it will also try to repair DRBD links in case a
  631. secondary node has rebooted. In addition it is responsible for archiving old
  632. cluster jobs, and it will restart any down Ganeti daemons that are appropriate
  633. for the current node. If the cluster parameter @code{maintain_node_health} is
  634. enabled, the watcher will also shutdown instances and DRBD devices if the node
  635. is declared offline by known master candidates.")))
  636. (define-record-type* <ganeti-cleaner-configuration>
  637. ganeti-cleaner-configuration make-ganeti-cleaner-configuration
  638. ganeti-cleaner-configuration?
  639. (ganeti ganeti-cleaner-configuration-ganeti ;<package>
  640. (default ganeti))
  641. (master-schedule ganeti-cleaner-configuration-master-schedule ;list | string
  642. ;; Run the master cleaner at 01:45 every day.
  643. (default "45 1 * * *"))
  644. (node-schedule ganeti-cleaner-configuration-node-schedule ;list | string
  645. ;; Run the node cleaner at 02:45 every day.
  646. (default "45 2 * * *")))
  647. (define ganeti-cleaner-jobs
  648. (match-lambda
  649. (($ <ganeti-cleaner-configuration> ganeti master-schedule node-schedule)
  650. (list
  651. #~(job #$@(match master-schedule
  652. ((? string?)
  653. #~(#$master-schedule))
  654. ((? list?)
  655. #~('#$master-schedule)))
  656. (lambda ()
  657. (system* #$(file-append ganeti "/sbin/ganeti-cleaner")
  658. "master")))
  659. #~(job #$@(match node-schedule
  660. ((? string?)
  661. #~(#$node-schedule))
  662. ((? list?)
  663. #~('#$node-schedule)))
  664. (lambda ()
  665. (system* #$(file-append ganeti "/sbin/ganeti-cleaner")
  666. "node")))))))
  667. (define ganeti-cleaner-service-type
  668. (service-type (name 'ganeti-cleaner)
  669. (extensions
  670. (list (service-extension mcron-service-type
  671. ganeti-cleaner-jobs)))
  672. (default-value (ganeti-cleaner-configuration))
  673. (description
  674. "@command{ganeti-cleaner} is a script that removes old files
  675. from the cluster. When called with @code{node} as argument it removes expired
  676. X509 certificates and keys from @file{/var/run/ganeti/crypto}, as well as
  677. outdated @command{ganeti-watcher} information.
  678. When called with @code{master} as argument, it instead removes files older
  679. than 21 days from @file{/var/lib/ganeti/queue/archive}.")))
  680. (define-record-type* <ganeti-configuration>
  681. ganeti-configuration make-ganeti-configuration
  682. ganeti-configuration?
  683. (ganeti ganeti-configuration-ganeti
  684. (default ganeti))
  685. (noded-configuration ganeti-configuration-noded-configuration
  686. (default (ganeti-noded-configuration)))
  687. (confd-configuration ganeti-configuration-confd-configuration
  688. (default (ganeti-confd-configuration)))
  689. (wconfd-configuration ganeti-configuration-wconfd-configuration
  690. (default (ganeti-wconfd-configuration)))
  691. (luxid-configuration ganeti-configuration-luxid-configuration
  692. (default (ganeti-luxid-configuration)))
  693. (rapi-configuration ganeti-configuration-rapi-configuration
  694. (default (ganeti-rapi-configuration)))
  695. (kvmd-configuration ganeti-configuration-kvmd-configuration
  696. (default (ganeti-kvmd-configuration)))
  697. (mond-configuration ganeti-configuration-mond-configuration
  698. (default (ganeti-mond-configuration)))
  699. (metad-configuration ganeti-configuration-metad-configuration
  700. (default (ganeti-metad-configuration)))
  701. (watcher-configuration ganeti-configuration-watcher-configuration
  702. (default (ganeti-watcher-configuration)))
  703. (cleaner-configuration ganeti-configuration-cleaner-configuration
  704. (default (ganeti-cleaner-configuration)))
  705. (file-storage-paths ganeti-configuration-file-storage-paths ;list of strings | gexp
  706. (default '()))
  707. (os ganeti-configuration-os ;list of <ganeti-os>
  708. (default '())))
  709. (define (ganeti-activation config)
  710. (with-imported-modules '((guix build utils))
  711. #~(begin
  712. (use-modules (guix build utils))
  713. (for-each mkdir-p
  714. '("/var/log/ganeti"
  715. "/var/log/ganeti/kvm"
  716. "/var/log/ganeti/os"
  717. "/var/lib/ganeti/rapi"
  718. "/var/lib/ganeti/queue"
  719. "/var/lib/ganeti/queue/archive"
  720. "/var/run/ganeti/bdev-cache"
  721. "/var/run/ganeti/crypto"
  722. "/var/run/ganeti/socket"
  723. "/var/run/ganeti/instance-disks"
  724. "/var/run/ganeti/instance-reason"
  725. "/var/run/ganeti/livelocks")))))
  726. (define ganeti-shepherd-services
  727. (match-lambda
  728. (($ <ganeti-configuration> _ noded confd wconfd luxid rapi kvmd mond metad)
  729. (append (ganeti-noded-service noded)
  730. (ganeti-confd-service confd)
  731. (ganeti-wconfd-service wconfd)
  732. (ganeti-luxid-service luxid)
  733. (ganeti-rapi-service rapi)
  734. (ganeti-kvmd-service kvmd)
  735. (ganeti-mond-service mond)
  736. (ganeti-metad-service metad)))))
  737. (define ganeti-mcron-jobs
  738. (match-lambda
  739. (($ <ganeti-configuration> _ _ _ _ _ _ _ _ _ watcher cleaner)
  740. (append (ganeti-watcher-jobs watcher)
  741. (ganeti-cleaner-jobs cleaner)))))
  742. (define-record-type* <ganeti-os>
  743. ganeti-os make-ganeti-os ganeti-os?
  744. (name ganeti-os-name) ;string
  745. (extension ganeti-os-extension) ;string
  746. (variants ganeti-os-variants ;list of <ganeti-os-variant>
  747. (default '())))
  748. (define-record-type* <ganeti-os-variant>
  749. ganeti-os-variant make-ganeti-os-variant ganeti-os-variant?
  750. (name ganeti-os-variant-name) ;string
  751. (configuration ganeti-os-variant-configuration)) ;<file-like>
  752. (define %debootstrap-interfaces-hook
  753. (file-append ganeti-instance-debootstrap
  754. "/share/doc/ganeti-instance-debootstrap/examples/interfaces"))
  755. ;; The GRUB hook shipped with instance-debootstrap does not work with GRUB2.
  756. ;; For convenience, provide one that work with modern Debians here.
  757. ;; Note: it would be neat to reuse Guix' bootloader infrastructure instead.
  758. (define %debootstrap-grub-hook
  759. (plain-file "grub"
  760. "#!/usr/bin/env bash
  761. CLEANUP=( )
  762. cleanup() {
  763. if [ ${#CLEANUP[*]} -gt 0 ]; then
  764. LAST_ELEMENT=$((${#CLEANUP[*]}-1))
  765. REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
  766. for i in $REVERSE_INDEXES; do
  767. ${CLEANUP[$i]}
  768. done
  769. fi
  770. }
  771. trap cleanup EXIT
  772. mount -t proc proc $TARGET/proc
  773. CLEANUP+=(\"umount $TARGET/proc\")
  774. mount -t sysfs sysfs $TARGET/sys
  775. CLEANUP+=(\"umount $TARGET/sys\")
  776. mount -o bind /dev $TARGET/dev
  777. CLEANUP+=(\"umount $TARGET/dev\")
  778. echo '
  779. GRUB_TIMEOUT_STYLE=menu
  780. GRUB_CMDLINE_LINUX_DEFAULT=\"console=ttyS0,115200 net.ifnames=0\"
  781. GRUB_TERMINAL=\"serial\"
  782. GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"
  783. ' >> $TARGET/etc/default/grub
  784. # This PATH is propagated into the chroot and necessary to make grub-install
  785. # and related commands visible.
  786. export PATH=\"/usr/sbin:/usr/bin:/sbin:/bin:$PATH\"
  787. chroot \"$TARGET\" grub-install $BLOCKDEV
  788. chroot \"$TARGET\" update-grub
  789. cleanup
  790. trap - EXIT
  791. "))
  792. (define %default-debootstrap-hooks
  793. `((10-interfaces . ,%debootstrap-interfaces-hook)
  794. (90-grub . ,%debootstrap-grub-hook)))
  795. (define %default-debootstrap-extra-pkgs
  796. ;; Packages suitable for a fully virtualized KVM guest.
  797. '("acpi-support-base" "udev" "linux-image-amd64" "openssh-server"
  798. "locales-all" "grub-pc"))
  799. (define-record-type* <debootstrap-configuration>
  800. debootstrap-configuration make-debootstrap-configuration
  801. debootstrap-configuration?
  802. (hooks debootstrap-configuration-hooks ;#f | gexp | '((name . gexp))
  803. (default %default-debootstrap-hooks))
  804. (proxy debootstrap-configuration-proxy (default #f)) ;#f | string
  805. (mirror debootstrap-configuration-mirror ;#f | string
  806. (default #f))
  807. (arch debootstrap-configuration-arch (default #f)) ;#f | string
  808. (suite debootstrap-configuration-suite ;#f | string
  809. (default "stable"))
  810. (extra-pkgs debootstrap-configuration-extra-pkgs ;list of strings
  811. (default %default-debootstrap-extra-pkgs))
  812. (components debootstrap-configuration-components ;list of strings
  813. (default '()))
  814. (generate-cache? debootstrap-configuration-generate-cache? ;Boolean
  815. (default #t))
  816. (clean-cache debootstrap-configuration-clean-cache ;#f | integer
  817. (default 14))
  818. (partition-style debootstrap-configuration-partition-style ;#f | symbol | string
  819. (default 'msdos))
  820. (partition-alignment debootstrap-configuration-partition-alignment ;#f | integer
  821. (default 2048)))
  822. (define (hooks->directory hooks)
  823. (match hooks
  824. ((? file-like?)
  825. hooks)
  826. ((? list?)
  827. (let ((names (map car hooks))
  828. (files (map cdr hooks)))
  829. (with-imported-modules '((guix build utils))
  830. (computed-file "hooks-union"
  831. #~(begin
  832. (use-modules (guix build utils)
  833. (ice-9 match))
  834. (mkdir-p #$output)
  835. (with-directory-excursion #$output
  836. (for-each (match-lambda
  837. ((name hook)
  838. (let ((file-name (string-append
  839. #$output "/"
  840. (symbol->string name))))
  841. ;; Copy to the destination to ensure
  842. ;; the file is executable.
  843. (copy-file hook file-name)
  844. (chmod file-name #o555))))
  845. '#$(zip names files))))))))
  846. (_ #f)))
  847. (define-gexp-compiler (debootstrap-configuration-compiler
  848. (file <debootstrap-configuration>) system target)
  849. (match file
  850. (($ <debootstrap-configuration> hooks proxy mirror arch suite extra-pkgs
  851. components generate-cache? clean-cache
  852. partition-style partition-alignment)
  853. (let ((customize-dir (hooks->directory hooks)))
  854. (gexp->derivation
  855. "debootstrap-variant"
  856. #~(call-with-output-file (ungexp output "out")
  857. (lambda (port)
  858. (display
  859. (string-append
  860. (ungexp-splicing
  861. `(,@(if proxy
  862. `("PROXY=" ,proxy "\n")
  863. '())
  864. ,@(if mirror
  865. `("MIRROR=" ,mirror "\n")
  866. '())
  867. ,@(if arch
  868. `("ARCH=" ,arch "\n")
  869. '())
  870. ,@(if suite
  871. `("SUITE=" ,suite "\n")
  872. '())
  873. ,@(if (not (null? extra-pkgs))
  874. `("EXTRA_PKGS=" ,(string-join extra-pkgs ",") "\n")
  875. '())
  876. ,@(if (not (null? components))
  877. `("COMPONENTS=" ,(string-join components ",") "\n")
  878. '())
  879. ,@(if customize-dir
  880. `("CUSTOMIZE_DIR=" ,customize-dir "\n")
  881. '())
  882. ,@(if generate-cache?
  883. '("GENERATE_CACHE=yes\n")
  884. '("GENERATE_CACHE=no\n"))
  885. ,@(if clean-cache
  886. `("CLEAN_CACHE=" ,(number->string clean-cache) "\n")
  887. '())
  888. ,@(if partition-style
  889. (if (symbol? partition-style)
  890. `("PARTITION_STYLE="
  891. ,(symbol->string partition-style) "\n")
  892. `("PARTITION_STYLE=" ,partition-style "\n"))
  893. '())
  894. ,@(if partition-alignment
  895. `("PARTITION_ALIGNMENT="
  896. ,(number->string partition-alignment) "\n")
  897. '()))))
  898. port)))
  899. #:local-build? #t)))))
  900. (define (ganeti-os->directory os)
  901. "Return the derivation to build the configuration directory to be installed
  902. in /etc/ganeti/instance-$os for OS."
  903. (let* ((name (ganeti-os-name os))
  904. (extension (ganeti-os-extension os))
  905. (variants (ganeti-os-variants os))
  906. (names (map ganeti-os-variant-name variants))
  907. (configs (map ganeti-os-variant-configuration variants)))
  908. (with-imported-modules '((guix build utils))
  909. (define builder
  910. #~(begin
  911. (use-modules (guix build utils)
  912. (ice-9 format)
  913. (ice-9 match)
  914. (srfi srfi-1))
  915. (mkdir-p #$output)
  916. (unless (null? '#$names)
  917. (let ((variants-dir (string-append #$output "/variants")))
  918. (mkdir-p variants-dir)
  919. (call-with-output-file (string-append variants-dir "/variants.list")
  920. (lambda (port)
  921. (format port "~a~%"
  922. (string-join '#$names "\n"))))
  923. (for-each (match-lambda
  924. ((name file)
  925. (symlink file
  926. (string-append variants-dir "/" name
  927. #$extension))))
  928. '#$(zip names configs))))))
  929. (computed-file (string-append name "-os") builder))))
  930. (define (ganeti-directory file-storage-file os)
  931. (let ((dirs (map ganeti-os->directory os))
  932. (names (map ganeti-os-name os)))
  933. (define builder
  934. #~(begin
  935. (use-modules (ice-9 match))
  936. (mkdir #$output)
  937. (when #$file-storage-file
  938. (symlink #$file-storage-file
  939. (string-append #$output "/file-storage-paths")))
  940. (for-each (match-lambda
  941. ((name dest)
  942. (symlink dest
  943. (string-append #$output "/instance-" name))))
  944. '#$(zip names dirs))))
  945. (computed-file "etc-ganeti" builder)))
  946. (define (file-storage-file paths)
  947. (match paths
  948. ((? null?) #f)
  949. ((? list?) (plain-file
  950. "file-storage-paths"
  951. (string-join paths "\n")))
  952. (_ paths)))
  953. (define (ganeti-etc-service config)
  954. (list `("ganeti" ,(ganeti-directory
  955. (file-storage-file
  956. (ganeti-configuration-file-storage-paths config))
  957. (ganeti-configuration-os config)))))
  958. (define (debootstrap-os variants)
  959. (ganeti-os
  960. (name "debootstrap")
  961. (extension ".conf")
  962. (variants variants)))
  963. (define (debootstrap-variant name configuration)
  964. (ganeti-os-variant
  965. (name name)
  966. (configuration configuration)))
  967. (define %default-debootstrap-variants
  968. (list (debootstrap-variant
  969. "default"
  970. (debootstrap-configuration))))
  971. (define (guix-os variants)
  972. (ganeti-os
  973. (name "guix")
  974. (extension ".scm")
  975. (variants variants)))
  976. (define (guix-variant name configuration)
  977. (ganeti-os-variant
  978. (name name)
  979. (configuration configuration)))
  980. (define %default-guix-variants
  981. (list (guix-variant
  982. "default"
  983. (file-append ganeti-instance-guix
  984. "/share/doc/ganeti-instance-guix/examples/dynamic.scm"))))
  985. ;; The OS configurations usually come with a default OS. To make them work
  986. ;; out of the box, follow suit.
  987. (define %default-ganeti-os
  988. (list (debootstrap-os %default-debootstrap-variants)
  989. (guix-os %default-guix-variants)))
  990. (define ganeti-service-type
  991. (service-type (name 'ganeti)
  992. (extensions
  993. (list (service-extension activation-service-type
  994. ganeti-activation)
  995. (service-extension shepherd-root-service-type
  996. ganeti-shepherd-services)
  997. (service-extension etc-service-type
  998. ganeti-etc-service)
  999. (service-extension profile-service-type
  1000. (compose list ganeti-configuration-ganeti))
  1001. (service-extension mcron-service-type
  1002. ganeti-mcron-jobs)))
  1003. (default-value (ganeti-configuration (os %default-ganeti-os)))
  1004. (description
  1005. "Ganeti is a family of services that are designed to run
  1006. on a fleet of machines and facilitate deployment and maintenance of virtual
  1007. servers (@dfn{instances}). It can migrate instances between nodes, automatically
  1008. restart failed instances, evacuate nodes, and much more.")))