aboutsummaryrefslogtreecommitdiff
path: root/sync
diff options
context:
space:
mode:
Diffstat (limited to 'sync')
-rw-r--r--sync/vps.scm286
1 files changed, 260 insertions, 26 deletions
diff --git a/sync/vps.scm b/sync/vps.scm
index 51fd91a..16be8cf 100644
--- a/sync/vps.scm
+++ b/sync/vps.scm
@@ -1,17 +1,245 @@
-(use-modules (gnu)
- (ice-9 textual-ports)
- (guix gexp))
-(use-package-modules ssh
- backup
- version-control)
-(use-service-modules networking
- ssh
- mcron
- admin
- mail
- web
- certbot
- cgit)
+(use-modules ((gnu) #:prefix gnu:)
+ ((guix) #:prefix guix:)
+ ((guix build utils) #:prefix utils:)
+ ((guix gexp) #:prefix gexp:)
+ ((srfi srfi-1) #:prefix srfi-1:)
+ ((ice-9 textual-ports) #:prefix textual-ports:)
+ ((ice-9 ftw) #:prefix ftw:)
+ ((ice-9 popen) #:prefix popen:)
+ ((ice-9 rdelim) #:prefix rdelim:)
+ ((ice-9 string-fun) #:prefix string-fun:))
+
+(gnu:use-package-modules ssh
+ backup
+ version-control)
+(gnu:use-service-modules networking
+ ssh
+ mcron
+ admin
+ mail
+ web
+ certbot
+ cgit)
+
+
+
+;; missing from the stdlib
+
+(define* (partial f #:rest args1)
+ (lambda* (#:rest args2)
+ (apply f (append args1 args2))))
+
+(define (every-pred-fn ps x)
+ (if (null? ps)
+ #t
+ (and ((car ps) x)
+ (every-pred-fn (cdr ps) x))))
+
+(define (every-pred . ps)
+ (partial every-pred-fn ps))
+
+(define (complement f)
+ (lambda* (#:rest args)
+ (not (apply f args))))
+
+
+
+;; custom extensions
+
+;; FIXME: with-open-pipe
+
+(define (slurp f)
+ (string-trim-both
+ (call-with-input-file f textual-ports:get-string-all)))
+
+(define (ignored? path)
+ (or (equal? "." path)
+ (equal? ".." path)))
+
+(define (dotfile? path)
+ (equal? #\. (string-ref path 0)))
+
+(define (list-directory path)
+ (ftw:scandir path
+ (every-pred (complement ignored?)
+ (complement dotfile?))))
+
+(define (hash-double-quote-reader _char port)
+ "Taken almost verbatim from let-over-lambda."
+ (let ((chars '()))
+ (do ((prev (read-char port) curr)
+ (curr (read-char port) (read-char port)))
+ ((and (equal? #\" prev)
+ (equal? #\# curr)))
+ (set! chars (cons prev chars)))
+ (list->string (reverse! chars))))
+
+(read-hash-extend #\" hash-double-quote-reader)
+
+;; (defun |#"-reader| (stream sub-char numarg)
+;; (declare (ignore sub-char numarg))
+;; (let (chars)
+;; (do ((prev (read-char stream) curr)
+;; (curr (read-char stream) (read-char stream)))
+;; ((and (char= prev #\") (char= curr #\#)))
+;; (push prev chars))
+;; (coerce (nreverse chars) 'string)))
+
+;; (set-dispatch-macro-character
+;; #\# #\" #'|#"-reader|)
+
+
+;; (define (heredoc-reader _char port)
+;; "Taken almost verbatim from let-over-lambda."
+;; (let ((chars '()))
+;; (do ((curr (read-char port)
+;; (read-char port)))
+;; ((equal? #\newline curr))
+;; (push! curr chars))
+;; (let* ((pattern (reverse! chars))
+;; (pointer pattern)
+;; (output '()))
+;; (do ((curr (read-char port)
+;; (read-char port)))
+;; ((null? pointer))
+;; (push! curr output)
+;; (set! pointer
+;; (if (equal? (car pointer) curr)
+;; (cdr pointer)
+;; pattern))
+;; ;; (if (null? pointer)
+;; ;; (return))
+;; )
+;; (list->string (reverse! output)))))
+
+;; (read-hash-extend #\> heredoc-reader)
+
+;; (defun |#>-reader| (stream sub-char numarg)
+;; (declare (ignore sub-char numarg))
+;; (let (chars)
+;; (do ((curr (read-char stream)
+;; (read-char stream)))
+;; ((char= #\newline curr))
+;; (push curr chars))
+;; (let* ((pattern (nreverse chars))
+;; (pointer pattern)
+;; (output))
+;; (do ((curr (read-char stream)
+;; (read-char stream)))
+;; ((null pointer))
+;; (push curr output)
+;; (setf pointer
+;; (if (char= (car pointer) curr)
+;; (cdr pointer)
+;; pattern))
+;; (if (null pointer)
+;; (return)))
+;; (coerce
+;; (nreverse
+;; (nthcdr (length pattern) output))
+;; 'string))))
+
+
+
+;; CI HTML generation
+
+(define ci-html-beginning
+ #"<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+
+ <style>
+ pre {
+ display: inline;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>
+ Build logs
+ </h1>"#)
+
+(define ci-html-ending
+ "</body>
+</html>")
+
+(define git-data-path "/srv/git")
+(define ci-data-path "/srv/ci")
+
+(define (ci-data-in-repo-notes path)
+ (utils:with-directory-excursion path
+ (let* ((port (popen:open-pipe* OPEN_READ "git" "notes" "list"))
+ (out (rdelim:read-string port))
+ (out-list (string-split (string-fun:string-replace-substring (string-trim-right out)
+ "\n"
+ " ")
+ #\space))
+ (relevant-commits (map srfi-1:first
+ (filter (compose odd? srfi-1:second)
+ (srfi-1:zip out-list
+ (iota (length out-list)))))))
+ (popen:close-pipe port)
+ (map (lambda (commit)
+ (let* ((data-port (popen:open-pipe* OPEN_READ "git" "notes" "--ref=refs/notes/ci-data" "show" commit))
+ (logs-port (popen:open-pipe* OPEN_READ "git" "notes" "--ref=refs/notes/ci-logs" "show" commit))
+ (data (string-split (string-trim-right (rdelim:read-string data-port))
+ #\space))
+ (logs (string-trim-right (rdelim:read-string logs-port))))
+ (popen:close-pipe data-port)
+ (popen:close-pipe logs-port)
+ (list (cons #:status (srfi-1:first data))
+ (cons #:filename (srfi-1:second data))
+ (cons #:logs logs))))
+ relevant-commits))))
+
+(define (generate-html-for-project name)
+ (string-append
+ "<h2 id=\"" name "\">
+ <a href=\"#" name "\">
+ " name "
+ </a>
+ </h2>
+ <ul>"
+ (apply
+ string-append
+ (map (lambda (data)
+ (let ((status (if (equal? "0" (assoc-ref data #:status)) "✅" "❌"))
+ (file (string-append name "/" (assoc-ref data #:filename))))
+ (string-append
+ "<li>
+ <a href=\"" file "\">
+ " status "
+ <pre>" file "</pre>
+ </a>
+ </li>")))
+ (ci-data-in-repo-notes (string-append git-data-path "/" name))))
+ "</ul>"))
+
+(define (generate-ci-index-html)
+ (call-with-output-file (string-append ci-data-path "/index.html")
+ (partial display
+ (string-append ci-html-beginning
+ (apply string-append
+ (map generate-html-for-project
+ (list-directory git-data-path)))
+ ci-html-ending))))
+
+(define (restore-logfiles)
+ (for-each (lambda (name)
+ (map (lambda (data)
+ (let* ((directory (string-append ci-data-path "/" name))
+ (filename (string-append directory "/" (assoc-ref data #:filename))))
+ (utils:mkdir-p directory)
+ (call-with-output-file filename
+ (partial display (assoc-ref data #:logs)))))
+ (ci-data-in-repo-notes (string-append git-data-path "/" name))))
+ (list-directory git-data-path)))
+
+
+
+;; OS configuration
(define ssh-public-key
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDF+uy407LKZAFnfFkJPRiOBzwV98qIEcKhITnLYhqfITfrJvcFVOY0/YDCrs6WHXyLdM29AoywVWsQ1qXiB7xQCwknPV8YZoCnJQcn0gvH8jbCk+C8Po0Rx846wbhL49qYolnmlhe+Uoy30j7XIJSDtPVO9d/hZqt2GPwGVJ98HLyY2ak+j4i1YkHr+mPFgnCaqCAzA374d1Bop18+YENYtMMU0k8hCsomwZny/7qNo4V8mjLxQAS8FvTuljxlthEpOM4Jsjl07yDLgE69kLvU7mmFi8EeC26e50N18Ouse82dZigtVhAMeLBhbJnQbDff4WfUBzSjpKjZPGcxoRaej3qSRbIkcMMqCOSlww6GcjRi+COvlpA4c1i4hKI15wHceoiKghDLA6jbaHfOqEMldflYl5gCVUIYzJ5XehZppH6L7PzO+L4suNs+aFjWPDZ0jqEtcyTmgTMea40p7wwz086ExnBDorbG79oDiJrWc+swJjXuVakS+fQjb3mPsCC/FgUhsxEtqiVfvLo2mphp47pOYvs64aUp3RV9muqQNuS4tEuP9V1urGTLtgPL26LEjF0oLu1ag0H+VZY5O/T9KRYvWre8IWbj/KkZYo1tJaGJyEVr0plmyzLBEy8b3Hu/6Wtq7yB0Eii60fxqFWC24nEkvs1V0cxDa+o6I2iA9w== eu@euandre.org")
@@ -19,10 +247,6 @@
(define user
"andreh")
-(define (slurp f)
- (string-trim-both
- (call-with-input-file f get-string-all)))
-
(define sudoers "\
root ALL=(ALL) ALL
%wheel ALL=NOPASSWD: ALL\n")
@@ -51,7 +275,8 @@ root ALL=(ALL) ALL
(string-append letsencrypt-prefix domain "/privkey.pem"))
(define opensmtpd-config
- (mixed-text-file "euandreh-smtpd.conf" "
+ ;; FIXME
+ (gexp:plain-file "euandreh-smtpd.conf" (string-append "
listen on eth0
# File comes from mail-aliases-service-type
table aliases file:/etc/aliases
@@ -60,7 +285,7 @@ accept for local alias <aliases> deliver to maildir
accept for any relay
pki " mail-domain " cert \"" (tls-pub-for mail-domain) "\"
-pki " mail-domain " key \"" (tls-priv-for mail-domain) "\""))
+pki " mail-domain " key \"" (tls-priv-for mail-domain) "\"")))
(define tls-prefixes
(list "www"
@@ -76,6 +301,14 @@ pki " mail-domain " key \"" (tls-priv-for mail-domain) "\""))
(string-append prefix "." tld))
tls-prefixes)))
+(define generate-ci-index-html-job
+ #~(job "*/5 * * * *"
+ generate-ci-index-html))
+
+(define restore-logfiles-job
+ #~(job "1 * * * *"
+ restore-logfiles))
+
(operating-system
(locale "fr_FR.UTF-8")
(timezone "America/Sao_Paulo")
@@ -104,7 +337,8 @@ pki " mail-domain " key \"" (tls-priv-for mail-domain) "\""))
`((,user ,(plain-file "id_rsa.pub" ssh-public-key))))))
(service mcron-service-type
(mcron-configuration
- (jobs (list))))
+ (jobs (list generate-ci-index-html-job
+ restore-logfiles-job))))
(service unattended-upgrade-service-type)
(service dhcp-client-service-type)
(service opensmtpd-service-type
@@ -157,16 +391,16 @@ pki " mail-domain " key \"" (tls-priv-for mail-domain) "\""))
(max-stats "year")
(nocache? #t)
(readme "README.md")
- ;()
+ ;()
;; (repositories
;; (list
;; (repository-cgit-configuration
;; ))
;; )
- ;; (map (lambda (f)
- ;; (repository-cgit-configuration (readme f)))
- ;; '("README.md" "README" "README.rst" "README.org"))
- ))
+ ;; (map (lambda (f)
+ ;; (repository-cgit-configuration (readme f)))
+ ;; '("README.md" "README" "README.rst" "README.org"))
+ ))
(simple-service 'init-srv-directories
activation-service-type
#~(begin