blob: 4b62fc9e3cd095e89d377260e204b53bec923e01 (
plain) (
tree)
|
|
(define-module (org euandre services)
#:use-module ((org euandre packages) #:prefix pkg:)
#:use-module ((org euandre queue) #:prefix q:)
#:use-module ((ice-9 match) #:prefix m:)
#:use-module ((ice-9 popen) #:prefix popen:)
#:use-module ((ice-9 textual-ports) #:prefix textual-ports:)
#:use-module ((gnu build linux-container) #:prefix container:)
#:use-module ((srfi srfi-1) #:prefix s1:)
#:use-module ((xyz euandreh heredoc) #:prefix heredoc:)
#:use-module (gnu)
#:use-module (guix build utils)
#:use-module (guix least-authority)
#:use-module (guix records)
#:export (<syskeep-configuration>
syskeep-configuration
make-syskeep-configuration
syskeep-configuration?
syskeep-configuration-package
syskeep-configuration-log-file
<binder-configuration>
binder-configuration
make-binder-configuration
binder-configuration?
binder-configuration-name
binder-configuration-package
binder-configuration-user
binder-configuration-group
binder-configuration-log-file
binder-configuration-data-directory
binder-configuration-run-directory
binder-configuration-run-in-container?
binder-configuration-container-name
binder-configuration-extra-mappings
<glaze-configuration>
glaze-configuration
make-glaze-configuration
glaze-configuration?
glaze-configuration-name
glaze-configuration-package
glaze-configuration-user
glaze-configuration-group
glaze-configuration-log-file
glaze-configuration-data-directory
glaze-configuration-run-directory
glaze-configuration-run-in-container?
glaze-configuration-container-name
glaze-configuration-extra-mappings
<untls-configuration>
untls-configuration
make-untls-configuration
untls-configuration?
untls-configuration-name
untls-configuration-package
untls-configuration-user
untls-configuration-group
untls-configuration-log-file
untls-configuration-data-directory
untls-configuration-run-directory
untls-configuration-run-in-container?
untls-configuration-container-name
untls-configuration-extra-mappings
<wscat-configuration>
wscat-configuration
make-wscat-configuration
wscat-configuration?
wscat-configuration-name
wscat-configuration-package
wscat-configuration-user
wscat-configuration-group
wscat-configuration-log-file
wscat-configuration-data-directory
wscat-configuration-run-directory
wscat-configuration-run-in-container?
wscat-configuration-container-name
wscat-configuration-extra-mappings
<papod-configuration>
papod-configuration
make-papod-configuration
papod-configuration?
papod-configuration-name
papod-configuration-package
papod-configuration-user
papod-configuration-group
papod-configuration-log-file
papod-configuration-data-directory
papod-configuration-run-directory
papod-configuration-run-in-container?
papod-configuration-container-name
papod-configuration-extra-mappings))
(use-package-modules
admin
version-control)
(use-service-modules
admin
mcron
shepherd)
(define-public (slurp path)
(call-with-input-file
path
textual-ports:get-string-all))
(define-public (str . rest)
(apply string-append rest))
(define-public (fmt . rest)
(apply format #f rest))
(define-public (user-accounts users)
(map (lambda (user)
(let ((name (s1:first user))
(comment (s1:second user))
(groups (s1:third user)))
(user-account
(name name)
(comment comment)
(group "users")
(supplementary-groups groups))))
users))
(define-public (users->keys users)
(let ((users-with-keys (filter (compose not null? cdddr)
users)))
(append
(map (lambda (user)
(let ((name (s1:first user))
(key (s1:fourth user)))
`(,name ,(plain-file (str name "-id_rsa.pub") key))))
users-with-keys)
`(("git" ,@(map (lambda (user)
(let ((name (s1:first user))
(key (s1:fourth user)))
(plain-file (str name "-git-id_rsa.pub")
(slurp key))))
users-with-keys))))))
(define (tuple->entry tuple)
(let* ((name (s1:first tuple))
(package (s1:second tuple))
(path (string-append "/etc/" name)))
(list
name
(computed-file
(string-append "syskeep-" name)
#~(begin
(use-modules
((ice-9 textual-ports) #:prefix textual-ports:))
(define (slurp p)
(call-with-input-file p textual-ports:get-string-all))
(define (spit p s)
(call-with-output-file
p
(lambda (port)
(display s port))))
(spit #$output
(slurp #$(file-append package path))))))))
(define (etc-entries package paths)
(map
tuple->entry
(map (lambda (path)
(list path package))
paths)))
(define-public (package-set symbols records)
(append
records
(map
(compose list specification->package+output symbol->string)
symbols)))
(define-public skeletons
(etc-entries
pkg:syskeep
'(".profile")))
(define-public base-services
(modify-services %base-services
(rottlog-service-type config =>
(rottlog-configuration
(inherit config)
(rc-file
(file-append q:rottlog-mailutils-sendmail "/etc/rc"))))))
(define-record-type* <syskeep-configuration>
syskeep-configuration
make-syskeep-configuration
syskeep-configuration?
(package syskeep-configuration-package (default pkg:syskeep))
(log-file syskeep-configuration-log-file (default "/var/log/cronjobs/cronjobs.log")))
(define (syskeep-profile config)
(match-record config <syskeep-configuration>
(package)
(package-set
'(parted
guile-heredoc
acl
bind:utils
knot:tools
file
git
lsof
moreutils
mailutils-sendmail
curl
make
borg
rsync
sqlite
strace
rlwrap
trash-cli
tree)
(list
package))))
(define (syskeep-rotations config)
(match-record config <syskeep-configuration>
(log-file)
(list
(log-rotation
(frequency 'weekly)
(files (list log-file))
(options '("rotate 52"))))))
(define (syskeep-cronjobs config)
(match-record config <syskeep-configuration>
()
(list
#~(job "0 0 * * *" "cronjob check")
#~(job "0 1 * * *" "cronjob env BORG_REPO=/mnt/backup/borg backup -q cron")
#~(job "0 2 * * *" "cronjob backup -q cron")
#~(job "0 3 * * 0" "cronjob gc")
#~(job "0 4 * * *" "cronjob reconfigure -U"))))
(define (syskeep-etc-files config)
(match-record config <syskeep-configuration>
(package)
(etc-entries
package
'("rc"
"known_hosts"
"ssh.conf"
"init.scm"
"gitconfig"))))
(define (syskeep-accounts config)
(match-record config <syskeep-configuration>
()
(list
(user-account
(name "git")
(group "git")
(system? #t)
(comment "External SSH Git user")
(home-directory "/src/ĝit")
(create-home-directory? #f)
(shell
(file-append git "/bin/git-shell")))
(user-group
(name "git")
(system? #t)))))
(define-public syskeep-service-type
(service-type
(name 'syskeep)
(extensions
(list
(service-extension rottlog-service-type
syskeep-rotations)
(service-extension mcron-service-type
syskeep-cronjobs)
(service-extension etc-service-type
syskeep-etc-files)
(service-extension account-service-type
syskeep-accounts)
(service-extension profile-service-type
syskeep-profile)))
(default-value (syskeep-configuration))
(description "Common configuration of maintained servers.")))
(define-record-type* <binder-configuration>
binder-configuration
make-binder-configuration
binder-configuration?
(name binder-configuration-name (default "binder"))
(package binder-configuration-package (default pkg:binder))
(user binder-configuration-user (default "binder"))
(group binder-configuration-group (default "binder"))
(log-file binder-configuration-log-file (default "/var/log/binder/binder.log"))
(data-directory binder-configuration-data-directory (default #f))
(run-directory binder-configuration-run-directory (default "/var/run/binder"))
(run-in-container? binder-configuration-run-in-container? (default #t))
(container-name binder-configuration-container-name (default "binder-container"))
(extra-mappings binder-configuration-extra-mappings (default '())))
(define-record-type* <glaze-configuration>
glaze-configuration
make-glaze-configuration
glaze-configuration?
(name glaze-configuration-name (default "glaze"))
(package glaze-configuration-package (default pkg:glaze))
(user glaze-configuration-user (default "glaze"))
(group glaze-configuration-group (default "glaze"))
(log-file glaze-configuration-log-file (default "/var/log/glaze/glaze.log"))
(data-directory glaze-configuration-data-directory (default #f))
(run-directory glaze-configuration-run-directory (default "/var/run/glaze"))
(run-in-container? glaze-configuration-run-in-container? (default #t))
(container-name glaze-configuration-container-name (default "glaze-container"))
(extra-mappings glaze-configuration-extra-mappings (default '())))
(define-record-type* <untls-configuration>
untls-configuration
make-untls-configuration
untls-configuration?
(name untls-configuration-name (default "untls"))
(package untls-configuration-package (default pkg:untls))
(user untls-configuration-user (default "untls"))
(group untls-configuration-group (default "untls"))
(log-file untls-configuration-log-file (default "/var/log/untls/untls.log"))
(data-directory untls-configuration-data-directory (default #f))
(run-directory untls-configuration-run-directory (default "/var/run/untls"))
(run-in-container? untls-configuration-run-in-container? (default #t))
(container-name untls-configuration-container-name (default "untls-container"))
(extra-mappings untls-configuration-extra-mappings (default '())))
(define-record-type* <wscat-configuration>
wscat-configuration
make-wscat-configuration
wscat-configuration?
(name wscat-configuration-name (default "wscat"))
(package wscat-configuration-package (default pkg:wscat))
(user wscat-configuration-user (default "wscat"))
(group wscat-configuration-group (default "wscat"))
(log-file wscat-configuration-log-file (default "/var/log/wscat/wscat.log"))
(data-directory wscat-configuration-data-directory (default #f))
(run-directory wscat-configuration-run-directory (default "/var/run/wscat"))
(run-in-container? wscat-configuration-run-in-container? (default #t))
(container-name wscat-configuration-container-name (default "wscat-container"))
(extra-mappings wscat-configuration-extra-mappings (default '())))
(define-record-type* <papod-configuration>
papod-configuration
make-papod-configuration
papod-configuration?
(name papod-configuration-name (default "papod"))
(package papod-configuration-package (default pkg:papod))
(user papod-configuration-user (default "papod"))
(group papod-configuration-group (default "papod"))
(log-file papod-configuration-log-file (default "/var/log/papod/papod.log"))
(data-directory papod-configuration-data-directory (default "/var/lib/papod"))
(run-directory papod-configuration-run-directory (default "/var/run/papod"))
(run-in-container? papod-configuration-run-in-container? (default #t))
(container-name papod-configuration-container-name (default "papod-container"))
(extra-mappings papod-configuration-extra-mappings (default '())))
(define-public (profile-for type)
(lambda (config)
(m:match config
(($ type _name package)
(list package)))))
(define-public (rotations-for type)
(lambda (config)
(m:match config
(($ type _name _package _user _group log-file)
(list
(log-rotation
(frequency 'weekly)
(files (list log-file))
(options '("rotate 5200"))))))))
(define-public (activation-for type)
(lambda (config)
(m:match config
(($ type name _package user _group log-file data-directory run-directory)
#~(begin
(use-modules (guix build utils))
(when #$log-file
(format (current-error-port)
"Creating ~a log directory for '~a'.~%" #$name #$log-file)
(mkdir-p (dirname #$log-file))
(when (not (file-exists? #$log-file))
(call-with-output-file #$log-file (const #t)))
(chmod #$log-file #o644))
(let ((user (getpwnam #$user)))
(when #$data-directory
(format (current-error-port)
"Creating ~a data directory '~a'.~%" #$name #$data-directory)
(mkdir-p #$data-directory)
(chown #$data-directory (passwd:uid user) (passwd:gid user))
(chmod #$data-directory #o750))
(when #$run-directory
(format (current-error-port)
"Creating ~a run directory '~a'.~%" #$name #$run-directory)
(mkdir-p #$run-directory)
(chown #$run-directory (passwd:uid user) (passwd:gid user))
(chmod #$run-directory #o755))))))))
(define-public (accounts-for type)
(lambda (config)
(m:match config
(($ type name _package user group)
(list
(user-group
(name group)
(system? #t))
(user-account
(name user)
(group group)
(system? #t)
(comment (format #f "The user for runtime execution of ~a code" name))
(home-directory "/var/empty")
(shell
(file-append shadow "/sbin/nologin"))))))))
(define-public (shepherd-services-for type)
(lambda (config)
(m:match config
(($ type name package user group log-file data-directory _run-directory run-in-container? container-name extra-mappings)
(list
(shepherd-service
(provision (list (string->symbol name)))
(requirement '())
(start
#~(make-forkexec-constructor ;; FIXME: add #:resource-limits
(list
#$(let ((bin (file-append package (string-append "/bin/" name))))
(if (not run-in-container?)
bin
(least-authority-wrapper
bin
#:user user
#:group group
#:name container-name
#:directory (or data-directory "/")
#:preserved-environment-variables
'()
#:mappings
(append
(if data-directory
(list
(file-system-mapping
(source data-directory)
(target source)
(writable? #t)))
(list))
extra-mappings)))))
#:user #$user
#:group #$group
#:log-file #$log-file
#:directory #$data-directory))
(stop #~(make-kill-destructor SIGKILL))
(documentation
(fmt "The Shepherd service that runs the server via \"~a\"." name))))))))
(define-public (service-type-for name type config extensions)
(service-type
(name name)
(extensions
(append
(list
(service-extension shepherd-root-service-type
(shepherd-services-for type))
(service-extension profile-service-type
(profile-for type))
(service-extension activation-service-type
(activation-for type))
(service-extension account-service-type
(accounts-for type))
(service-extension rottlog-service-type
(rotations-for type)))
extensions))
(default-value config)
(description
(fmt "The top-level generic system service, generated for ~a code.
It includes:
- the Shepherd service for starting, stopping and reloading the service;
- activation script for setting up the initial directories and permissions;
- the group and account for running the production service;
- log management (storage and rotation) for logs produced by the running services.
The default configuration should provide sane values for all of these."
name))))
(define-public binder-service-type
(service-type-for 'binder <binder-configuration> (binder-configuration) '()))
(define-public glaze-service-type
(service-type-for 'glaze <glaze-configuration> (glaze-configuration) '()))
(define-public untls-service-type
(service-type-for 'untls <untls-configuration> (untls-configuration) '()))
(define-public wscat-service-type
(service-type-for 'wscat <wscat-configuration> (wscat-configuration) '()))
(define-public papod-service-type
(service-type-for 'papod <papod-configuration> (papod-configuration) '()))
|