(define-module (org euandre packages)
#:use-module ((gnu build linux-container) #:prefix container:)
#:use-module ((guix licenses) #:prefix licenses:)
#:use-module ((guix transformations) #:prefix transformations:)
#:use-module ((ice-9 match) #:prefix m:)
#:use-module ((ice-9 textual-ports) #:prefix textual-ports:)
#:use-module ((org euandre queue) #:prefix q:)
#:use-module ((srfi srfi-1) #:prefix s1:)
#:use-module (gnu)
#:use-module (guix build-system gnu)
#:use-module (guix git-download)
#:use-module (guix least-authority)
#:use-module (guix packages)
#:use-module (guix records)
#:use-module (guix utils)
#:export (<syskeep-configuration>
syskeep-configuration
make-syskeep-configuration
syskeep-configuration?
syskeep-configuration-package
syskeep-configuration-log-file
<transactor-configuration>
transactor-configuration
make-transactor-configuration
transactor-configuration?
transactor-configuration-package
transactor-configuration-user
transactor-configuration-group
transactor-configuration-port
transactor-configuration-log-file
transactor-configuration-data-directory
transactor-configuration-run-in-container?
transactor-configuration-container-name
<git-configuration>
git-configuration
make-git-configuration
git-configuration?
git-configuration-package
git-configuration-user
git-configuration-group
git-configuration-export-all?
git-configuration-base-path
git-configuration-user-path
git-configuration-run-in-container?
git-configuration-container-name
<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-options
binder-configuration-listen-socket
binder-configuration-upstream-socket
<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-options
glaze-configuration-listen-socket
glaze-configuration-upstream-socket
<hsts-configuration>
hsts-configuration
make-hsts-configuration
hsts-configuration?
hsts-configuration-name
hsts-configuration-package
hsts-configuration-user
hsts-configuration-group
hsts-configuration-log-file
hsts-configuration-data-directory
hsts-configuration-run-directory
hsts-configuration-run-in-container?
hsts-configuration-container-name
hsts-configuration-options
hsts-configuration-listen-socket
hsts-configuration-upstream-socket
<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-options
untls-configuration-listen-socket
untls-configuration-upstream-socket
<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-options
wscat-configuration-listen-socket
wscat-configuration-upstream-socket
<cicd-configuration>
cicd-configuration
make-cicd-configuration
cicd-configuration?
cicd-configuration-name
cicd-configuration-package
cicd-configuration-user
cicd-configuration-group
cicd-configuration-log-file
cicd-configuration-data-directory
cicd-configuration-run-directory
cicd-configuration-run-in-container?
cicd-configuration-container-name
<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-options
papod-configuration-listen-socket
papod-configuration-upstream-socket
fmt
str
service-type-for))
(use-package-modules
admin
base
bittorrent
gawk
guile
java
sqlite
texinfo
version-control)
(use-service-modules
admin
mcron
shepherd
sysctl)
(define-public (mklist x)
(if (not x)
'()
(if (pair? x)
x
(list x))))
(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 mktorrent-latest
((transformations:options->transformation
'((with-commit . "mktorrent=de7d011b35458de1472665f50b96c9cf6c303f39")))
mktorrent))
(define-public (pkg name version checksum)
(package
(name name)
(version version)
(source
(origin
(method git-fetch)
(uri
(git-reference
(url
(str "git://euandre.org/" name))
(commit version)))
(sha256
(base32 checksum))
(file-name
(git-file-name name version))))
(build-system gnu-build-system)
(arguments
(list
#:strip-binaries? #f
#:make-flags
#~(list
"-e"
(string-append "CC=" #$(cc-for-target))
(string-append "PREFIX=" #$output)
(string-append "VERSION=" #$version))
#:phases
#~(modify-phases %standard-phases
(delete 'configure))))
(synopsis #f) ;; FIXME: get
(description #f) ;; from tarball!
(home-page (str "https://euandre.org/s/" name "/"))
(license licenses:agpl3+)))
(define-public eut
(pkg
"eut"
"ec7e36c2eb4a05c188fd222a1a775ef6f55be6b8"
"1knz14jkx8yc7fv5m2apshfsn3xym55vb78wx3kgq061jy58nxfd"))
(define-public remembering
(pkg
"remembering"
"e1570edd3cdaa040f9664adb315f72e33f8b67c2"
"0y20flrbjh5gbbzl7h3rimg8jwy2ikgkj03yxclj8qg8mq2f9f4a"))
(define-public cage
(pkg
"cage"
"c0482531fc16a55715b759b695d27d555d927ab8"
"1v5m7xqfb14y283mlc2kd714hnih1dwcmjcf4i6j52pphjscilys"))
(define-public nicely
(pkg
"nicely"
"8c963ba56495a382480ab96423df22beb19cb592"
"0c9vqjxlh4gjh09pavs5dscgxcnbii7jp1d8v0jhq3qjz9lf3k2w"))
(define-public q
(pkg
"q"
"d13bcb36bc84de95ebb9e8c27605c09b08c35cc5"
"1jbg9f6dwkkcjxbhc3a1pnaas6xgd1f0hiv95h6hchgs88phwssl"))
(define-public syskeep
(pkg
"syskeep"
"2215cc0999e43b32751bc493f2fe9d2e8c822170"
"0p38fb8m35kjp9fj7bmwcayf9r4638q5fcin18ny7y65scij4jbb"))
(define-public backupit
(pkg
"backupit"
"331f37ba29b1cb317b9bf1984e0efce40b14c03f"
"1zhwp1widxghjimg838fp7mffrsj97a5w22fy0ydr0pzh3rjzs23"))
(define-public cicd
(pkg
"cicd"
"63d46fe31f3ae7b7eed1a2c801448160fe9e77d8"
"00brrbm6s45nqpbw2sigcwjwj2dgyl0rvagmgrgj930y9qv2nn31"))
(define-public guile-heredoc
(package
(inherit
(pkg
"guile-heredoc"
"065435cdce609604e33b879b9be3e81ab89f3e7b"
"179qq17mgi4kakhj9w1dk26afljh5yad4j9ih9d8wms70x6h211m"))
(native-inputs
(list
guile-3.0
texinfo))))
(define-public adoc
(package
(inherit
(pkg
"adoc"
"fab32a816259c943802ffa4c041ac63ac34e646a"
"04sk5bafw2h969v4fl9qzc67m4sjdlrw87xdliv7rny7v9d53zi8"))
(propagated-inputs
(append
(format-inputs (list eut))
(normalize-inputs '(ruby-asciidoctor tidy-html))))))
(define-public eslaides
(pkg
"eslaides"
"40eb0452fd7689d1c40e4d53c1473fd42195cc49"
"0g4qdcfmk8asi1fzr1yk8khpngg9cg21i14xblxfisqsfaq5jycb"))
(define-public mkwb
(package
(inherit
(pkg
"mkwb"
"1c36a265c6b34c28c424eb0bc11ba3b0f9b932d0"
"1w8f3rsncxrb383i7pwg8bxrijvvg7q2l6b0fgjfdv1rs4xzlmqw"))
(propagated-inputs
(format-inputs (list eut adoc eslaides)))))
(define-public (mkwbsite pkg)
(package
(inherit pkg)
(native-inputs
(append
(format-inputs (list mkwb mktorrent-latest))
(normalize-inputs '(gnupg jq rsync po4a gettext ghostscript moreutils))))
(arguments
(substitute-keyword-arguments (package-arguments pkg)
((#:phases phases)
#~(modify-phases #$phases
(add-before 'build 'sethome-ghostscript
(lambda _
(setenv "HOME" (getcwd))))))))))
(define-public euandre.org
(mkwbsite
(pkg
"euandre.org"
"6e493d66649925fccaa351f65ee6cac2dedf264f"
"05isnj2mmwg6k1qd94r3yaycy556f5d7br3f2vdmriqazrgj0grg")))
(define-public papo.im
(mkwbsite
(pkg
"papo.im"
"fa07fa576e07b4cc6b7c9123bd3a6c91e6afc609"
"084w89v15nmr45nv9av8pz7iq99aw3ggaxr0gzqfjbskb3wvvkml")))
(define-public datomic
(let ((p (pkg
"datomic"
"13edba0fa2bd4c3847160809499ce837f52d1264"
"158sqawmbszawa132bhfghzlkhd3b0bicdg5dr93v56vvm4i25kl")))
(package
(inherit p)
(arguments
(substitute-keyword-arguments (package-arguments p)
((#:phases phases)
#~(modify-phases #$phases
(add-after 'install 'wrap-program
(lambda* _
(wrap-program
(string-append #$output "/bin/transactor")
`("PATH" ":" =
(,(string-append #$coreutils "/bin")
,(string-append #$gawk "/bin")
,(string-append #$openjdk23 "/bin")
,(string-append #$sed "/bin")
,(string-append #$sqlite-next "/bin")))))))))))))
(define-public (format-inputs l)
(map (lambda (p)
(list (package-name p)
p
"out"))
l))
(define-public (normalize-inputs l)
(map (compose (lambda (l)
(cons (package-name (car l))
l))
list
specification->package+output
symbol->string)
l))
(define-public (gopkgbs name inputs version checksum)
(let ((p (pkg name version checksum)))
(package
(inherit p)
(arguments
(substitute-keyword-arguments (package-arguments p)
((#:phases phases)
#~(modify-phases #$phases
(add-before 'build 'setenv-golang
(lambda _
(define (path->flags option)
(let ((search-path (getenv "GOLIBPACKPATH")))
(string-join
(map (lambda (path)
(string-append option " " path))
(if search-path
(string-split search-path #\:)
'()))
" ")))
(setenv "GOCFLAGS" (path->flags "-I"))
(setenv "GOLDFLAGS" (path->flags "-L"))))))))
(native-inputs
(append
(format-inputs
(list
eut
q:gol))
(normalize-inputs
'(gettext
po4a
ruby-asciidoctor))
inputs))
(native-search-paths
(list
(search-path-specification
(variable "GOLIBPACKPATH")
(files
(list "lib/go"))))))))
(define-public gotext
(gopkgbs
"gotext"
(format-inputs (list))
"25af4baaab8db74ba809c863e93dd56e6ffb23ed"
"1cwh5fc45dii6mpg4fr6a3fdqy37ib63ax8srfhr9jwzw6majha2"))
(define-public uuid
(gopkgbs
"uuid"
(format-inputs (list gotext))
"8cba50466b837d2f4149ca22d6645f6d6127c63a"
"139d8vwd9l6hha2cc5skhh799c5b0n1l0dkp8r8m6nisla8bpals"))
(define-public gobang
(gopkgbs
"gobang"
(format-inputs (list gotext uuid))
"79011564903bd53bb036dea4c1f0745e40efb73c"
"1rjnvz2wznkxcdhdf0h6mvza2wj2hpirb4vzjxs49g7mfhsp394h"))
(define-public (gopkg name inputs version checksum)
(gopkgbs
name
(append inputs (format-inputs (list gotext uuid gobang)))
version
checksum))
(define-public pds
(gopkg
"pds"
(format-inputs (list))
"aa855d0dc1c62094d0fbf750f60b5b9f776b47d2"
"0k10pqqz0pmd4w7lq4qnwr96fl3vhi3c0b4f41knwaslr2lv17xl"))
(define-public urubu
(gopkg
"urubu"
(format-inputs (list))
"b2351328e54d4793d6691382079a9895dc84696d"
"1aqrg165qsi0pfihjqndjzqrdd4ipjydjm71rzccz34xf7k7m3ch"))
(define-public stm
(gopkg
"stm"
(format-inputs (list pds))
"cb89a691031acd7beac798a74d174b572b22319e"
"1ld84nchnbh7g1dcjw2hvzpqwlpa450rs3i3i0x918911264wcv9"))
(define-public scrypt
(gopkg
"scrypt"
(format-inputs (list q:scryptkdf))
"6071b32e9a6ab214a18c7ef7ffe59c0d6d68e9ca"
"0iv4lalmrn3hb71wzrgqgji72f4dwklbaphj3h8nj6lr1zpjzvyq"))
(define-public golite
(gopkg
"golite"
(format-inputs (list q:sqlitex))
"170dfdf2783c8c2431861f77193c92f40860ea07"
"13y9vzxhr8jn7px2sgfgjapykr258q12ckf458qi0rkcma1vsz59"))
(define-public fiinha
(gopkg
"fiinha"
(format-inputs (list q:sqlitex golite))
"24fafda1fe9e962c8e508220c7023dabd5407e4a"
"1h4ig562flpqsxi52h04npj0nm6038chby8nd2lb8vj1nhiq77al"))
(define-public cracha
(gopkg
"cracha"
(format-inputs (list q:sqlitex golite q:scryptkdf scrypt fiinha))
"84865499aa10aa42c8b9ac06325a05dd8354f458"
"0hsnw1rng4ccdmgp4vfgn8jnyp05mqs5z7qvw7micia07li73m70"))
(define-public binder
(gopkg
"binder"
(normalize-inputs '(socat lsof))
"a45f1e444f6f053635315c8f6fad6ad465f8b0dc"
"0vwmhb76cw499751228jkd6057bj57wkg1jlwal13mm4x0453mjv"))
(define-public glaze
(gopkg
"glaze"
(format-inputs (list))
"24e540da26aad0fb6fc6a8845b1cf83757b15dd0"
"0idyds5wh9rzav7n8q64gwhlsjrzh0kgwp98rwq5rkrc08dqv3sb"))
(define-public hsts
(gopkg
"hsts"
(format-inputs (list))
"783845f84860968dd5e0f971fea42045c8b8e58c"
"0c17x9mdka213fkkccxff1wld38qhpfr8gs2h3kzg0s8wnnfvn42"))
(define-public untls
(gopkg
"untls"
(format-inputs (list))
"b66067d503bac4cfeda83331e045d9c79d8b43c1"
"09pmvaw6rslvasaa6k598aki6c01anfgazzzkcggisdj775wl6in"))
(define-public wscat
(gopkg
"wscat"
(format-inputs (list))
"9cc15130935dfaa6b58231ec708a2c71e54c3968"
"1z85p3v40368jyphip067rlx1m1gpmbvh5d4rjvx1lz81ncpsyf8"))
(define-public gistatic
(gopkg
"gistatic"
(format-inputs (list))
"1eec478135876b7f325c507d1284aa5782bad09d"
"1hsdqaszkr52cy80yid5i7r7fa4crc7qkpd5mglzbd9v4v2sispy"))
(define-public chat.papo.im
(package
(inherit
(pkg
"chat.papo.im"
"f9c959b2d8e36460395a425a51d480fac635c5ec"
"0h2y0kdfzpsgi64zi7brnj1p0dqz0fx4ksvy57wakr7pvv6rpf64"))
(native-inputs
(normalize-inputs '(node)))))
(define-public papod
(gopkg
"papod"
(format-inputs
(list stm pds golite q:sqlitex scrypt q:scryptkdf fiinha cracha))
"3da803b0ff65cf2af71b810ec8fbd28307280d79"
"1ppg1hg9qlkxg7mzsca0j3wdml5773s2x2h8d1j25hk7cg8kqiaj"))
(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")
(slurp 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 (str "/etc/" name)))
(list
name
(computed-file
(str "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)
(let ((tuples (map (lambda (path)
(list path package))
paths)))
(map tuple->entry tuples)))
(define-public (package-set symbols records)
(append
%base-packages
records
(map
(compose list specification->package+output symbol->string)
symbols)))
(define-public skeletons
(etc-entries
syskeep
'(".profile")))
(define-public base-services
(append
(list
#;
(service fail2ban-service-type))
%base-services))
(define-public (activation-gexp name user 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-record-type* <syskeep-configuration>
syskeep-configuration
make-syskeep-configuration
syskeep-configuration?
(package syskeep-configuration-package (default syskeep))
(tld syskeep-configuration-tld (default #f))
(secrets-user syskeep-configuration-secrets-user (default "secrets-keeper"))
(secrets-group syskeep-configuration-secrets-group (default "secrets-keeper"))
(become-secrets-group syskeep-configuration-become-secrets-group (default "become-secrets-keeper"))
(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
glibc-locales
guile-heredoc
acl
bind:utils
knot:tools
certbot
jq
file
git
lsof
moreutils
mailutils-sendmail
curl
make
borg
pv
rsync
sqlite
strace
rlwrap
trash-cli
tree)
(list
uuid
backupit
eut
nicely
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 env BORG_REPO=/mnt/backup/borg backupit -q -t cron")
#~(job "0 1 * * *" "cronjob backupit -q -t cron")
#~(job "0 2 * * *" "cronjob reconfigure")
#~(job "0 3 * * 0" "cronjob gc")
#~(job "0 4 * * *" "cronjob guix pull -v3")
#~(job "0 5 * * 0" "cronjob reconfigure")
#~(job "0 5 * * *" "cronjob check"))))
(define (syskeep-etc-files config)
(match-record config <syskeep-configuration>
(package)
(etc-entries
package
'("rc.sh"
"backupit.txt"
"ssh.conf"
"init.scm"
"gitconfig"))))
(define (syskeep-accounts config)
(match-record config <syskeep-configuration>
(secrets-user secrets-group become-secrets-group)
(list
(user-account
(name secrets-user)
(group secrets-group)
(system? #t)
(comment "System account used to manage production secrets")
(home-directory "/var/empty")
(create-home-directory? #f)
(shell
(file-append shadow "/sbin/nologin")))
(user-group
(name secrets-group)
(system? #t))
(user-group
(name become-secrets-group)
(system? #t)))))
(define (syskeep-activation config)
(match-record config <syskeep-configuration>
(tld log-file)
(let ((privkey-path (fmt "../../opt/secrets/root@~a.id_rsa.txt" tld)))
#~(begin
#$(activation-gexp "syskeep" "root" log-file #f #f)
(define (dir target)
(format (current-error-port)
"Creating directory: \"~a\".~%" target)
(mkdir-p target))
(define (link from to)
(format (current-error-port)
"Symlink: \"~a\" -> \"~a\".~%" to from)
(when (file-exists? to)
(delete-file to))
(symlink from to))
(dir "/var/crash")
(chmod "/var/crash" #o777)
(link "mnt/production/opt" "/opt")
(link "mnt/production/srv" "/srv")
(link "../mnt/production/mail" "/var/mail")
(dir "/root/.ssh")
(link #$privkey-path "/root/.ssh/id_rsa")
(link "../../etc/ssh.conf" "/root/.ssh/config")
(link "../../etc/id_rsa.pub" "/root/.ssh/id_rsa.pub")
(link "../../etc/known_hosts" "/root/.ssh/known_hosts")))))
(define-public (syskeep-sysctl _config)
'(("kernel/core_pattern" . "/var/crash/core-%t-%e-%p-%s-%u-%g")))
(define-public syskeep-sudoers-file
(plain-file "sudoers-syskeep" "\
root ALL=(ALL) ALL
%wheel ALL= ALL
%wheel ALL= NOPASSWD: /run/current-system/profile/bin/reconfigure, /run/current-system/profile/bin/herd, /run/current-system/profile/bin/repo
%become-secrets-keeper ALL=(secrets-keeper) NOPASSWD: /run/current-system/profile/bin/rsync, /run/current-system/profile/bin/setfacl, /run/current-system/profile/bin/rm
%git ALL=(cicd) NOPASSWD: /run/current-system/profile/bin/cicd
"))
(define-public syskeep-service-type
(service-type
(name 'syskeep)
(extensions
(list
(service-extension log-rotation-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 activation-service-type
syskeep-activation)
(service-extension sysctl-service-type
syskeep-sysctl)
(service-extension profile-service-type
syskeep-profile)))
(default-value (syskeep-configuration))
(description "Common configuration of maintained servers.")))
(define-record-type* <transactor-configuration>
transactor-configuration
make-transactor-configuration
transactor-configuration?
(package transactor-configuration-package (default datomic))
(user transactor-configuration-user (default "transactor"))
(group transactor-configuration-group (default "peer"))
(port transactor-configuration-port (default 50200))
(log-file transactor-configuration-log-file (default "/var/log/transactor/transactor.log"))
(base-directory transactor-configuration-data-directory (default "/var/lib/transactor"))
(run-in-container? transactor-configuration-run-in-container? (default #t))
(container-name transactor-configuration-container-name (default "datomic-container")))
(define-public (transactor-command config)
(match-record config <transactor-configuration>
(package user group base-directory run-in-container? container-name)
(let ((bin (file-append package "/bin/transactor")))
(if (not run-in-container?)
bin
(least-authority-wrapper
bin
#:user user
#:group group
#:directory base-directory
#:name container-name
#:namespaces (s1:fold delq container:%namespaces '(net))
#:preserved-environment-variables
'()
#:mappings
(list
(file-system-mapping
(source base-directory)
(target source)
(writable? #t))))))))
(define-public (transactor-shepherd-services config)
(match-record config <transactor-configuration>
(port user group log-file base-directory)
(list
(shepherd-service
(provision '(transactor))
(requirement '())
(start
#~(make-forkexec-constructor
(list #$(transactor-command config)
"-p" (number->string #$port)
(string-append #$base-directory "/data/storage.db"))
#:user #$user
#:group #$group
#:log-file #$log-file
#:directory #$base-directory))
(stop #~(make-kill-destructor))
(documentation "Daemon transactor process.")))))
(define-public (transactor-activation config)
(match-record config <transactor-configuration>
(user log-file base-directory)
#~(begin
(use-modules
(guix build utils))
(format
(current-error-port)
"Creating Transactor data directories under: \"~a\".~%"
#$base-directory)
(mkdir-p/perms (string-append #$base-directory "/data")
(getpwnam #$user)
#o750)
(mkdir-p/perms (string-append #$base-directory "/backup")
(getpwnam #$user)
#o750)
(format
(current-error-port)
"Creating Transactor log directory for \"~a\".~%"
#$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))))
(define-public (transactor-accounts config)
(match-record config <transactor-configuration>
(user group)
(list
(user-account
(name user)
(group group)
(comment "Datomic transactor system user")
(create-home-directory? #f)
(shell
(file-append shadow "/sbin/nologin"))
(system? #t))
(user-group
(name group)
(system? #t)))))
(define (transactor-cronjobs config)
(match-record config <transactor-configuration>
(base-directory)
(let ((from (string-append base-directory "/data/storage.db"))
(to (string-append base-directory "/backup")))
(list
#~(job "0 23 * * *" (format #f "cronjob datomic backup ~a ~a" #$from #$to))
#~(job "0 6 * * *" (format #f "cronjob datomic gc ~a" #$from))))))
(define-public transactor-service-type
(service-type
(name 'transactor)
(extensions
(list
(service-extension shepherd-root-service-type
transactor-shepherd-services)
(service-extension activation-service-type
transactor-activation)
(service-extension account-service-type
transactor-accounts)
(service-extension mcron-service-type
transactor-cronjobs)
(service-extension profile-service-type
(compose list transactor-configuration-package))))
(default-value (transactor-configuration))
(description "Transactor service.")))
(define-record-type* <git-configuration>
git-configuration
make-git-configuration
git-configuration?
(package git-configuration-package (default git))
(user git-configuration-user (default "git"))
(group git-configuration-group (default "git"))
(export-all? git-configuration-export-all? (default #f))
(base-path git-configuration-base-path (default "/srv/git"))
(user-path git-configuration-user-path (default #f))
(run-in-container? git-configuration-run-in-container? (default #f))
(container-name git-configuration-container-name (default "git-container"))
(run-server? git-configuration-run-server? (default #f)))
(define-public (git-command config)
(match-record config <git-configuration>
(package user group base-path run-in-container? container-name)
(let ((bin (file-append package "/bin/git")))
(if (not run-in-container?)
bin
(least-authority-wrapper
bin
#:user user
#:group group
#:name container-name
#:directory base-path
#:preserved-environment-variables
'()
#:mappings
(list
(file-system-mapping
(source base-path)
(target source)
(writable? #t))))))))
(define-public (git-shepherd-services config)
(match-record config <git-configuration>
(user group export-all? base-path user-path run-server?)
(if (not run-server?)
(list)
(list
(shepherd-service
(provision '(git))
(requirement '(networking))
(start
#~(make-forkexec-constructor
(list #$(git-command config)
"daemon" "--syslog" "--reuseaddr"
#$@(mklist (and export-all? "--export-all"))
#$@(mklist (and base-path (str "--base-path=" base-path)))
#$@(mklist (and user-path (str "--user-path=" user-path))))
#:user #$user
#:group #$group))
(documentation "Daemon process of the git:// protocol."))))))
(define-public (git-accounts config)
(match-record config <git-configuration>
(user group base-path)
(list
(user-account
(name user)
(group group)
(system? #t)
(comment "External SSH Git service user")
(home-directory base-path)
(create-home-directory? #f))
(user-group
(name group)
(system? #t)))))
(define-public git-service-type
(service-type
(name 'git)
(extensions
(list
(service-extension shepherd-root-service-type
git-shepherd-services)
(service-extension account-service-type
git-accounts)
(service-extension profile-service-type
(compose list git-configuration-package))))
(default-value (git-configuration))
(description "Better git:// service.")))
(define-record-type* <binder-configuration>
binder-configuration
make-binder-configuration
binder-configuration?
(name binder-configuration-name (default "binder"))
(package binder-configuration-package (default 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"))
(options binder-configuration-options (default '()))
(listen-socket binder-configuration-listen-socket (default "0.0.0.0:4443"))
(upstream-socket binder-configuration-upstream-socket (default "/var/run/untls/untls.socket")))
(define-record-type* <glaze-configuration>
glaze-configuration
make-glaze-configuration
glaze-configuration?
(name glaze-configuration-name (default "glaze"))
(package glaze-configuration-package (default 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 "/var/lib/glaze"))
(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"))
(options glaze-configuration-options (default '()))
(listen-socket glaze-configuration-listen-socket (default "/var/run/glaze/glaze.socket"))
(upstream-socket glaze-configuration-upstream-socket (default #f)))
(define-record-type* <hsts-configuration>
hsts-configuration
make-hsts-configuration
hsts-configuration?
(name hsts-configuration-name (default "hsts"))
(package hsts-configuration-package (default hsts))
(user hsts-configuration-user (default "hsts"))
(group hsts-configuration-group (default "hsts"))
(log-file hsts-configuration-log-file (default "/var/log/hsts/hsts.log"))
(data-directory hsts-configuration-data-directory (default #f))
(run-directory hsts-configuration-run-directory (default "/var/run/hsts"))
(run-in-container? hsts-configuration-run-in-container? (default #t))
(container-name hsts-configuration-container-name (default "hsts-container"))
(options hsts-configuration-options (default '()))
(listen-socket hsts-configuration-listen-socket (default "/var/run/hsts/hsts.socket"))
(upstream-socket hsts-configuration-upstream-socket (default #f)))
(define-record-type* <untls-configuration>
untls-configuration
make-untls-configuration
untls-configuration?
(name untls-configuration-name (default "untls"))
(package untls-configuration-package (default 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"))
(options untls-configuration-options (default '()))
(listen-socket untls-configuration-listen-socket (default "/var/run/untls/untls.socket"))
(upstream-socket untls-configuration-upstream-socket (default #f)))
(define-record-type* <wscat-configuration>
wscat-configuration
make-wscat-configuration
wscat-configuration?
(name wscat-configuration-name (default "wscat"))
(package wscat-configuration-package (default 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"))
(options wscat-configuration-options (default '()))
(listen-socket wscat-configuration-listen-socket (default "/var/run/wscat/wscat.socket"))
(upstream-socket wscat-configuration-upstream-socket (default "/var/run/papod/papod.socket")))
(define-public (profile-for config-type)
(lambda (config)
(m:match config
(($ config-type _name package)
(list package)))))
(define-public (rotations-for config-type)
(lambda (config)
(m:match config
(($ config-type _name _package _user _group log-file)
(list
#;
(log-rotation
(frequency 'weekly)
(files (list log-file))
(options '("rotate 5200"))))))))
(define-public (activation-for config-type)
(lambda (config)
(m:match config
(($ config-type name _package user _group log-file data-directory
run-directory)
(activation-gexp name user log-file data-directory run-directory)))))
(define-public (accounts-for config-type)
(lambda (config)
(m:match config
(($ 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")
(create-home-directory? #f)
(shell
(file-append shadow "/sbin/nologin"))))))))
(define-public (cmd-for config-type config)
(m:match config
(($ config-type name package user group _log-file data-directory
_run-directory run-in-container? container-name)
(let ((bin (file-append package (str "/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
(mklist
(and data-directory
(file-system-mapping
(source data-directory)
(target source)
(writable? #t))))))))))
(define-public (shepherd-services-for config-type)
(lambda (config)
(m:match config
(($ config-type name _package user group log-file data-directory
_run-directory _run-in-container? _container-name options
listen-socket upstream-socket)
(list
(shepherd-service
(provision (list (string->symbol name)))
(requirement '(networking))
(auto-start? #f)
(start
#~(make-forkexec-constructor
(list #$(cmd-for config-type config)
#$@options
#$@(mklist listen-socket)
#$@(mklist upstream-socket))
#:user #$user
#:group #$group
#:log-file #$log-file
#:directory #$data-directory))
(documentation
(fmt "The Shepherd service that runs the server via \"~a\"." name))))))))
(define-public (service-type-for name config-type config extensions)
(service-type
(name name)
(extensions
(append
(list
(service-extension shepherd-root-service-type
(shepherd-services-for config-type))
(service-extension profile-service-type
(profile-for config-type))
(service-extension activation-service-type
(activation-for config-type))
(service-extension account-service-type
(accounts-for config-type))
(service-extension log-rotation-service-type
(rotations-for config-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 (without-shepherd-services lst)
(filter (lambda (extension)
(not (eq? shepherd-root-service-type
(service-extension-target extension))))
lst))
(define-public (replacing-shepherd-services service fn)
(service-type
(inherit service)
(extensions
(append
(without-shepherd-services
(service-type-extensions service))
(list
(service-extension shepherd-root-service-type
fn))))))
(define-public (with-services-from-args service config-type args)
(replacing-shepherd-services
service
(lambda (config)
(m:match config
(($ config-type _name _package user group log-file data-directory)
(map (lambda (tuple)
(let ((provision (s1:first tuple))
(args (s1:second tuple)))
(shepherd-service
(provision provision)
(requirement '(networking))
(auto-start? #f)
(start
#~(make-forkexec-constructor
(list #$(cmd-for config-type config)
#$@args)
#:user #$user
#:group #$group
#:log-file #$log-file
#:directory #$data-directory)))))
args))))))
(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 hsts-service-type
(service-type-for 'hsts <hsts-configuration> (hsts-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-record-type* <cicd-configuration>
cicd-configuration
make-cicd-configuration
cicd-configuration?
(name cicd-configuration-name (default "cicd"))
(package cicd-configuration-package (default cicd))
(user cicd-configuration-user (default "cicd"))
(group cicd-configuration-group (default "cicd"))
(log-file cicd-configuration-log-file (default "/var/log/cicd/cicd.log"))
(data-directory cicd-configuration-data-directory (default "/var/lib/cicd"))
(run-directory cicd-configuration-run-directory (default "/var/run/cicd"))
(run-in-container? cicd-configuration-run-in-container? (default #f))
(container-name cicd-configuration-container-name (default "cicd")))
(define (cicd-profile config)
(match-record config <cicd-configuration>
(package)
(list
q
package)))
(define (cicd-shepherd-services config)
(match-record config <cicd-configuration>
(user group log-file data-directory)
(list
(shepherd-service
(provision '(cicd))
(requirement '())
(auto-start? #f)
(start
#~(make-forkexec-constructor
(list
#$(cmd-for <cicd-configuration> config)
"daemon")
#:user #$user
#:group #$group
#:log-file #$log-file
#:directory #$data-directory))
(documentation "The background daemon service that powers the CI.")))))
(define-public cicd-service-type
(service-type
(name 'cicd)
(extensions
(list
(service-extension shepherd-root-service-type
cicd-shepherd-services)
(service-extension profile-service-type
cicd-profile)
(service-extension activation-service-type
(activation-for <cicd-configuration>))
(service-extension account-service-type
(accounts-for <cicd-configuration>))
(service-extension log-rotation-service-type
(rotations-for <cicd-configuration>))))
(default-value (cicd-configuration))
(description (fmt "The CI agent service that backs a Git server."))))
(define-record-type* <papod-configuration>
papod-configuration
make-papod-configuration
papod-configuration?
(name papod-configuration-name
(default "papod"))
(package papod-configuration-package
(default 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"))
(options papod-configuration-options
(default '()))
(listen-socket papod-configuration-listen-socket
(default "/var/run/papod/papod.socket"))
(upstream-socket papod-configuration-upstream-socket
(default #f)))
#;
(define-public papod-service-type
(pkg:service-type-for 'papod
<papod-configuration>
(papod-configuration)
'()))
(list
mktorrent-latest
remembering
eut
cage
backupit
nicely
syskeep
q
cicd
guile-heredoc
adoc
eslaides
mkwb
euandre.org
datomic
gotext
uuid
gobang
pds
stm
golite
binder
glaze
hsts
untls
wscat
gistatic
urubu
fiinha
cracha
papo.im
chat.papo.im
papod)