(define-module (gnu services cloud-init) #:use-module (gnu packages bash) #:use-module (gnu packages python-web) #:use-module (gnu services) #:use-module (gnu services shepherd) #:use-module (guix gexp) #:use-module (guix records) #:export (cloud-init-configuration cloud-init-service cloud-init-service-type)) (define-record-type* cloud-init-configuration make-cloud-init-configuration cloud-init-configuration? (cloud-init cloud-init-configuration-cloud-init ;file-like (default python-cloud-init)) (init-modules cloud-init-configuration-init-modules ;list of symbols (default '(seed_random growpart resizefs disk_setup mounts set_hostname update_hostname users_groups ssh set_passwords))) (config-modules cloud-init-configuration-config-modules ;list of symbols (default '())) (final-modules cloud-init-configuration-final-modules ;list of symbols (default '(ssh_authkey_fingerprints))) (extra-configuration-files cloud-init-configuration-extra-configuration-files ;list of file-likes (default '()))) (define %cloud-dir "/etc/cloud") (define %cloud-cfg (string-append %cloud-dir "/cloud.cfg")) (define %cloud-run (mixed-text-file "run.sh" "#!" (file-append bash "/bin/bash") "\n\nset -euo pipefail\n\n" (file-append python-cloud-init "/bin/cloud-init") " init --local\n" (file-append python-cloud-init "/bin/cloud-init") " init\n" (file-append python-cloud-init "/bin/cloud-init") " modules --mode config\n" (file-append python-cloud-init "/bin/cloud-init") " modules --mode final\n")) (define %cloud-cfg-d (string-append %cloud-dir "/cloud.cfg.d")) (define (cloud-init-initialization init-modules config-modules final-modules extra) "Return the gexp to initialize the cloud-init configuration files" #~(begin (use-modules (srfi srfi-1) (srfi srfi-2) (guix build utils)) (define reduce-modules (lambda (mods) (string-join (map (lambda (mod) (string-append "\n - " (symbol->string mod))) mods)))) (mkdir-p #$%cloud-cfg-d) (copy-file #$%cloud-run (string-append #$%cloud-dir "/run.sh")) (chmod (string-append #$%cloud-dir "/run.sh") #o755) (unless (null? '(#$@extra)) (for-each (lambda (file) (symlink (cadr file) (string-append #$%cloud-cfg-d "/" (car file)))) '(#$@extra))) (call-with-output-file #$%cloud-cfg (lambda (p) (unless (null? '(#$@init-modules)) (display (string-append "cloud_init_modules:" (reduce-modules '(#$@init-modules)) "\n\n") p)) (unless (null? '(#$@config-modules)) (display (string-append "cloud_config_modules:" (reduce-modules '(#$@config-modules)) "\n\n") p)) (unless (null? '(#$@final-modules)) (display (string-append "cloud_final_modules:" (reduce-modules '(#$@final-modules)) "\n\n") p)))))) (define (cloud-init-activation config) "Return the activation gexp for CONFIG." #~(begin (use-modules (guix build utils)) #$(cloud-init-initialization (cloud-init-configuration-init-modules config) (cloud-init-configuration-config-modules config) (cloud-init-configuration-final-modules config) (cloud-init-configuration-extra-configuration-files config)))) (define (cloud-init-service config) "Return a for cloud-init with CONFIG." (define cloud-init (cloud-init-configuration-cloud-init config)) (list (shepherd-service (documentation "cloud-init service") (provision '(cloud-init)) (requirement '(networking)) (one-shot? #t) (start #~(fork+exec-command (list (string-append #$%cloud-dir "/run.sh")) #:log-file (string-append "/var/log/cloud-init.log") #:environment-variables ' ("PATH=/run/current-system/profile/bin:/run/current-system/profile/sbin:")))))) (define cloud-init-service-type (service-type (name 'cloud-init) (default-value (cloud-init-configuration)) (description "cloud init") (extensions (list (service-extension shepherd-root-service-type cloud-init-service) (service-extension activation-service-type cloud-init-activation)))))