summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile15
-rw-r--r--src/config/conf.env16
-rw-r--r--src/config/conf.env.in16
-rw-r--r--src/config/gitconfig11
-rw-r--r--src/config/init.scm6
-rw-r--r--src/config/known_hosts.txt5
-rw-r--r--src/config/profile.sh5
-rw-r--r--src/config/rc.sh80
-rw-r--r--src/config/ssh.conf6
-rw-r--r--src/guix/channels.scm4
-rw-r--r--src/guix/packages.scm55
-rw-r--r--src/guix/services.scm187
-rw-r--r--src/guix/system.scm448
-rwxr-xr-xsrc/scripts/backup.sh149
-rwxr-xr-xsrc/scripts/check.sh92
-rwxr-xr-xsrc/scripts/cicd.sh168
-rwxr-xr-xsrc/scripts/cronjob.sh169
-rwxr-xr-xsrc/scripts/deploy.sh72
-rwxr-xr-xsrc/scripts/gc.sh146
-rwxr-xr-xsrc/scripts/reconfigure.sh146
-rwxr-xr-xsrc/scripts/report.sh260
22 files changed, 91 insertions, 1969 deletions
diff --git a/.gitignore b/.gitignore
index 71084a0..be567ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-/packages
-/system
+/*.scm
+/*.sentinel
/src/secrets/*.txt
diff --git a/Makefile b/Makefile
index 4de1700..ecd9dcb 100644
--- a/Makefile
+++ b/Makefile
@@ -39,12 +39,14 @@ repo-secrets.txt = $(repo-secrets.txt.gpg:.gpg=)
derived-assets = \
+ packages.scm.sentinel \
+ system.scm.sentinel \
side-assets = \
$(prod-secrets.txt) \
$(repo-secrets.txt) \
- packages \
- system \
+ packages.scm \
+ system.scm \
@@ -58,9 +60,12 @@ $(derived-assets) src/config/conf.env: Makefile
src/config/tld.txt: Makefile
echo '$(TLD)' > $@
-packages system: src/guix/packages.scm src/guix/system.scm
- rm -f $@*
- guix build -r $@ -v3 -Kf src/guix/$@.scm
+packages.scm.sentinel: src/guix/packages.scm
+system.scm.sentinel: src/guix/packages.scm src/guix/system.scm
+packages.scm.sentinel system.scm.sentinel:
+ rm -f `basename $@ .sentinel`*
+ guix build -v3 -r`basename $@ .sentinel` -Kf src/guix/`basename $@ .sentinel`
+ touch $@
.SUFFIXES: .stripped
src/keys/SSH/root@$(TLD).id_rsa.pub.stripped: \
diff --git a/src/config/conf.env b/src/config/conf.env
deleted file mode 100644
index b60173e..0000000
--- a/src/config/conf.env
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-NAME='papo.im'
-TLD='papo.im'
-URL='papo.im'
-OFFSITE_SSH='00000@aa0000.rsync.net'
-OUT_SUFFIX=''
-PRIV_SUFFIX=''
-CI_SUFFIX="ci"
-
-HTML_OUTDIR_TOP="/srv/www/$OUT_SUFFIX"
-HTML_OUTDIR_PRIV="$HTML_OUTDIR_TOP$PRIV_SUFFIX"
-HTML_OUTDIR_CI="$HTML_OUTDIR_TOP/$CI_SUFFIX"
-HOMEPAGE="https://$TLD/$OUT_SUFFIX/"
-CGIT_URL="https://$TLD/git/$NAME/commit/?id="
-REPO_NAME="$NAME.git"
diff --git a/src/config/conf.env.in b/src/config/conf.env.in
deleted file mode 100644
index e54daef..0000000
--- a/src/config/conf.env.in
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-NAME='@NAME@'
-TLD='@TLD@'
-URL='@URL@'
-OFFSITE_SSH='@OFFSITE_SSH@'
-OUT_SUFFIX=''
-PRIV_SUFFIX=''
-CI_SUFFIX="ci"
-
-HTML_OUTDIR_TOP="/srv/www/$OUT_SUFFIX"
-HTML_OUTDIR_PRIV="$HTML_OUTDIR_TOP$PRIV_SUFFIX"
-HTML_OUTDIR_CI="$HTML_OUTDIR_TOP/$CI_SUFFIX"
-HOMEPAGE="https://$TLD/$OUT_SUFFIX/"
-CGIT_URL="https://$TLD/git/$NAME/commit/?id="
-REPO_NAME="$NAME.git"
diff --git a/src/config/gitconfig b/src/config/gitconfig
deleted file mode 100644
index f1f1eb3..0000000
--- a/src/config/gitconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-[init]
- defaultBranch = main
-[user]
- email = ci@$TLD
- name = "Git CI"
-[advice]
- detachedHead = false
-[receive]
- advertisePushOptions = true
-[uploadpack]
- allowAnySHA1InWant = true
diff --git a/src/config/init.scm b/src/config/init.scm
deleted file mode 100644
index 9e962e8..0000000
--- a/src/config/init.scm
+++ /dev/null
@@ -1,6 +0,0 @@
-(use-modules
- (ice-9 colorized)
- (ice-9 readline))
-
-(activate-colorized)
-(activate-readline)
diff --git a/src/config/known_hosts.txt b/src/config/known_hosts.txt
deleted file mode 100644
index 74ba219..0000000
--- a/src/config/known_hosts.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# rsync.net public keys
-# Verified in 2023-03-08 at:
-# https://www.rsync.net/resources/fingerprints.txt
-
-hk-s020.rsync.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILcPl9x9JfRFwsn09NnDw/xBZbAN80ZQck+h6AqlVqPH
diff --git a/src/config/profile.sh b/src/config/profile.sh
deleted file mode 100644
index 1dca8b2..0000000
--- a/src/config/profile.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-# shellcheck source=/dev/null
-. /etc/rc
-ln -fs .profile .bashrc
diff --git a/src/config/rc.sh b/src/config/rc.sh
deleted file mode 100644
index b44d3d1..0000000
--- a/src/config/rc.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-
-# shellcheck source=/dev/null
-. /etc/profile
-. /etc/conf.env
-
-export XDG_PREFIX=~/.usr
-export XDG_CACHE_HOME="$XDG_PREFIX"/var/cache
-export XDG_CONFIG_HOME="$XDG_PREFIX"/etc
-export XDG_DATA_HOME="$XDG_PREFIX"/share
-export XDG_STATE_HOME="$XDG_PREFIX"/state
-export XDG_LOG_HOME="$XDG_PREFIX"/var/log
-
-
-HOME_PARENT="$(dirname "$HOME")"
-if [ "$HOME_PARENT" = '/home' ] || [ "$HOME_PARENT" = '/' ]; then
- mkdir -p \
- "$XDG_CONFIG_HOME" \
- "$XDG_CACHE_HOME" \
- "$XDG_DATA_HOME" \
- "$XDG_LOG_HOME" \
- "$XDG_STATE_HOME"/ssh/conn
-fi
-
-
-GUIX_PROFILE="$XDG_CONFIG_HOME"/guix/current
-if [ -r "$GUIX_PROFILE"/etc/profile ]; then
- # shellcheck source=/dev/null
- . "$GUIX_PROFILE"/etc/profile
-fi
-
-export ENV=~/.profile
-export HISTSIZE=-1
-export HISTCONTROL=ignorespace:ignoredups
-export EDITOR=vi
-export VISUAL="$EDITOR"
-export PAGER='less -R'
-
-export EXINIT='
- " set number
- " set autoindent
- set ruler
- set showmode
- set showmatch
-'
-
-export HISTFILE="$XDG_STATE_HOME"/bash-history
-export LESSHISTFILE="$XDG_STATE_HOME"/lesshst
-export RLWRAP_HOME="$XDG_CACHE_HOME"/rlwrap
-export GUILE_HISTORY="$XDG_STATE_HOME"/guile-history
-
-HOSTNAME="$(hostname)"
-export BORG_REPO="$OFFSITE_SSH:borg/$HOSTNAME"
-export BORG_REMOTE_PATH='borg1'
-export BORG_PASSCOMMAND='cat /opt/secrets/borg-passphrase.txt'
-
-export GIT_CONFIG_GLOBAL=/etc/gitconfig
-
-unalias -a
-alias l='ls -lahF --color'
-alias grep='grep --color=auto'
-alias diff='diff --color=auto'
-alias watch='watch --color '
-alias man='MANWIDTH=$((COLUMNS > 80 ? 80 : COLUMNS)) man'
-alias less='less -R'
-alias tree='tree -aC'
-alias mv='mv -i'
-alias e='vi'
-
-alias sqlite='rlwrap sqlite3'
-alias guile='guile -l /etc/init.scm'
-
-error_marker() {
- STATUS=$?
- if [ "$STATUS" != 0 ]; then
- printf ' (!! %s !!) ' "$STATUS"
- fi
-}
-export PS1='`error_marker`\T \w/
-\u@\H\$ '
diff --git a/src/config/ssh.conf b/src/config/ssh.conf
deleted file mode 100644
index ca41df0..0000000
--- a/src/config/ssh.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-Host *
- ServerAliveInterval 30
- ServerAliveCountMax 20
- ControlMaster auto
- ControlPath ${XDG_STATE_HOME}/ssh/conn/%r@%h:%p
- ControlPersist 1h
diff --git a/src/guix/channels.scm b/src/guix/channels.scm
index 16a9c7d..697eb4f 100644
--- a/src/guix/channels.scm
+++ b/src/guix/channels.scm
@@ -1,8 +1,8 @@
(append
(list
(channel
- (name 'org-euandre)
- (url "git://euandre.org/package-repository")
+ (name 'EuAndreh)
+ (url "git://euandre.org/packages")
(branch "main")
(introduction
(make-channel-introduction
diff --git a/src/guix/packages.scm b/src/guix/packages.scm
index 7458488..31bdaca 100644
--- a/src/guix/packages.scm
+++ b/src/guix/packages.scm
@@ -1,35 +1,22 @@
(define-module (packages)
- #:use-module ((ice-9 textual-ports) #:prefix textual-ports:)
- #:use-module ((guix licenses) #:prefix licenses:)
- #:use-module ((org euandre packages) #:prefix packages:)
- #:use-module ((org euandre queue) #:prefix q:)
#:use-module ((org euandre packages) #:prefix pkg:)
+ #:use-module ((org euandre services) #:prefix serv:)
#:use-module (gnu)
- #:use-module (guix build-system gnu)
- #:use-module (guix download)
#:use-module (guix packages)
#:use-module (guix utils))
-(use-package-modules
- golang
- golang-xyz
- networking
- sqlite)
+(use-package-modules)
-(define (slurp f)
- (string-trim-both
- (call-with-input-file
- f
- textual-ports:get-string-all)))
-
-(define (file name s)
- (slurp (string-append "src/versions/" name "/" s)))
+(define (cat name s)
+ (string-trim-right
+ (serv:slurp
+ (string-append "src/versions/" name "/" s))))
(define (go-latest package)
(let* ((name (package-name package))
- (version (file name "version"))
- (checksum (file name "sha256")))
+ (version (cat name "version"))
+ (checksum (cat name "sha256")))
(package/inherit package
(version version)
(source
@@ -55,12 +42,20 @@
(string-append "CC=" #$(cc-for-target)))))))))
-(map go-latest
- (list
- pkg:gobang
- pkg:golite
- pkg:binder
- pkg:glaze
- pkg:untls
- pkg:wscat
- pkg:papod))
+(define-public gobang (go-latest pkg:gobang))
+(define-public golite (go-latest pkg:golite))
+(define-public binder (go-latest pkg:binder))
+(define-public glaze (go-latest pkg:glaze))
+(define-public untls (go-latest pkg:untls))
+(define-public wscat (go-latest pkg:wscat))
+(define-public papod (go-latest pkg:papod))
+
+
+(list
+ gobang
+ golite
+ binder
+ glaze
+ untls
+ wscat
+ papod)
diff --git a/src/guix/services.scm b/src/guix/services.scm
deleted file mode 100644
index 1e5ae4e..0000000
--- a/src/guix/services.scm
+++ /dev/null
@@ -1,187 +0,0 @@
-(define-module (services)
- #: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 srfi-1:)
- #:use-module ((xyz euandreh heredoc) #:prefix heredoc:)
- #:use-module (gnu)
- #:use-module (guix build utils)
- #:use-module (guix least-authority)
- #:use-module (guix records))
-(use-package-modules
- admin)
-(use-service-modules
- admin
- mcron
- shepherd)
-(heredoc:enable-syntax)
-
-
-(define +working-dir+
- (if (directory-exists? "/opt/deploy/current")
- "/opt/deploy/current"
- (canonicalize-path ".")))
-
-(add-to-load-path
- (string-append +working-dir+ "/src/infrastructure/guix"))
-(use-modules
- ((packages) #:prefix packages:))
-
-
-
-(define-record-type* <papo-configuration>
- papo-configuration
- make-papo-configuration
- papo-configuration?
- (package papo-configuration-package (default packages:papo))
- (user papo-configuration-user (default "papo"))
- (group papo-configuration-group (default "papo"))
- (config-dirname papo-configuration-config (default "papo"))
- (port papo-configuration-port (default 6666))
- (log-file papo-configuration-log-file (default "/var/log/papo.log"))
- (data-directory papo-configuration-data-directory (default "/var/lib/papo"))
- (run-directory papo-configuration-run-directory (default "/var/run/papo"))
- (run-in-container? papo-configuration-run-in-container? (default #t))
- (container-name papo-configuration-container-name (default "papo-container"))
- (container-namespaces papo-configuration-container-namespaces (default container:%namespaces))
- (extra-mappings papo-configuration-extra-mappings (default '())))
-
-(define (papo-etc-files config)
- (match-record config <papo-configuration>
- ()
- `(("papo.json" ,(plain-file "papo.json" "")))))
-
-(define (papo-log-rotations config)
- (match-record config <papo-configuration>
- (log-file)
- (list
- (log-rotation
- (frequency 'weekly)
- (files (list log-file))
- (options '("rotate 5200"))))))
-
-(define (papo-activation config)
- (match-record config <papo-configuration>
- (user log-file data-directory run-directory)
- #~(begin
- (use-modules (guix build utils))
- (format (current-error-port)
- "Creating papo 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)
- (let ((user (getpwnam #$user)))
- (format (current-error-port)
- "Creating papo data directory '~a'.~%" #$data-directory)
- (mkdir-p #$data-directory)
- (chown #$data-directory (passwd:uid user) (passwd:gid user))
- (chmod #$data-directory #o750)
- (format (current-error-port)
- "Creating papo run directory '~a'.~%" #$run-directory)
- (mkdir-p #$run-directory)
- (chown #$run-directory (passwd:uid user) (passwd:gid user))
- (chmod #$run-directory #o755)))))
-
-(define (papo-cronjobs _config)
- (list))
-
-(define (papo-accounts config)
- (match-record config <papo-configuration>
- (user group)
- (list
- (user-group
- (name group)
- (system? #t))
- (user-account
- (name user)
- (group group)
- (system? #t)
- (comment "The user for runtime execution of papo code")
- (home-directory "/var/empty")
- (shell
- (file-append shadow "/sbin/nologin"))))))
-
-(define (wrapped-command config)
- (match-record config <papo-configuration>
- (package data-directory
- run-in-container? container-name container-namespaces extra-mappings)
- (let ((bin (file-append package "/bin/papo")))
- (if (not run-in-container?)
- bin
- (least-authority-wrapper
- bin
- #:name container-name
- #:namespaces container-namespaces
- #:directory data-directory
- #:preserved-environment-variables
- '()
- #:mappings
- (append
- (list
- (file-system-mapping
- (source data-directory)
- (target source)
- (writable? #t))
- (file-system-mapping
- (source (file-append glibc-locales "/lib/locale"))
- (target "/run/current-system/locale")))
- extra-mappings))))))
-
-(define (exec-action config . static-args)
- (match-record config <papo-configuration>
- (user group log-file data-directory)
- #~(lambda dynamic-args
- (fork+exec-command
- (append '(#$@static-args) dynamic-args)
- #:user #$user
- #:group #$group
- #:directory #$data-directory
- #:log-file #$log-file))))
-
-(define (papo-shepherd-services config)
- (let ((cmd (wrapped-command config)))
- (list
- (shepherd-service
- (provision '(papo))
- (requirement '())
- (start (exec-action config cmd "ircd"))
- (stop #~(make-kill-destructor SIGKILL))
- (documentation
- #"-
- The Shepherd service that runs the server via "papo-ircd"."#)))))
-
-(define-public papo-service-type
- (service-type
- (name 'papo)
- (extensions
- (list
- (service-extension shepherd-root-service-type
- papo-shepherd-services)
- (service-extension etc-service-type
- papo-etc-files)
- (service-extension profile-service-type
- (compose list papo-configuration-package))
- (service-extension activation-service-type
- papo-activation)
- (service-extension account-service-type
- papo-accounts)
- (service-extension mcron-service-type
- papo-cronjobs)
- (service-extension rottlog-service-type
- papo-log-rotations)))
- (default-value (papo-configuration))
- (description
- #"-
- The top-level system service for papo code.
-
- It includes:
- - the Shepherd service for starting, stopping and reloading the
- service ("papo");
- - a list of cronjobs to be added to the system for sending documents
- proactively;
- - activation script for setting up the initial directories and permissions;
- - the "papo" group and "papo" account for running the production service;
- - log management (storage and rotation) for logs produced by the running services.
-
- The defaults of <papo-configuration> provide sane values for all of these."#)))
diff --git a/src/guix/system.scm b/src/guix/system.scm
index f5c2368..bb0faee 100644
--- a/src/guix/system.scm
+++ b/src/guix/system.scm
@@ -1,23 +1,15 @@
(use-modules
- ((ice-9 textual-ports) #:prefix textual-ports:)
((srfi srfi-1) #:prefix s1:)
((xyz euandreh heredoc) #:prefix heredoc:)
- ((org euandre queue) #:prefix queue:)
- (gnu)
- (guix build-system trivial)
- (guix build utils)
- (guix packages))
+ ((org euandre queue) #:prefix q:)
+ ((org euandre services) #:prefix serv:)
+ (gnu))
(use-package-modules
- admin
- ssh
version-control)
(use-service-modules
- admin
certbot
cgit
- dns
mail
- mcron
networking
security
ssh
@@ -25,380 +17,68 @@
(heredoc:enable-syntax)
-(define +ipv4+ "216.238.73.1")
-(define +ipv6+ "2001:19f0:b400:1582:5400:04ff:fea9:370e")
+
+(define (path s)
+ ;; src/guix/system.scm + ../../../ = ./
+ (serv:str (dirname (dirname (dirname (current-filename)))) "/" s))
(define +users+
- '(("andre" "EuAndreh" ("wheel" "become-deployer" "become-secrets-keeper"))
- ("laisse" "Laísses" ())))
+ `(("andre" "EuAndreh" ("wheel") ,(path "src/keys/SSH/andre.pub.txt"))))
-(define +working-dir+
- (if (directory-exists? "/opt/deploy/current")
- "/opt/deploy/current"
- (canonicalize-path ".")))
-(add-to-load-path
- (string-append +working-dir+ "/src/guix"))
+(add-to-load-path (dirname (current-filename)))
(use-modules
- ((packages) #:prefix packages:)
- ((services) #:prefix services:))
-
-
-(define (str . rest)
- (apply string-append rest))
+ ((packages) #:prefix packages:))
-(define (fmt . rest)
- (apply format #f rest))
-
-(define (path s)
- (str +working-dir+ "/" s))
-
-(define (slurp s)
- (call-with-input-file
- s
- textual-ports:get-string-all))
(define file
- (compose slurp path))
+ (compose serv:slurp path))
(define +tld+
- (string-trim-right
- (file "src/config/tld.txt")))
-
-
-(define +user-accounts+
- (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 (ssh-file-for user)
- (let ((name (s1:first user)))
- (path (fmt "src/keys/SSH/~a.pub.txt" name))))
-
-(define +authorized-keys+
- (let ((users-with-keys
- (map (lambda (user)
- `(,@user ,(slurp (ssh-file-for user))))
- (filter (lambda (user)
- (file-exists? (ssh-file-for user)))
- +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")
- key)))
- users-with-keys))))))
-
-(define (script name content)
- (package
- (name name)
- (version "latest")
- (source #f)
- (build-system trivial-build-system)
- (arguments
- (list
- #:modules '((guix build utils))
- #:builder
- #~(begin
- (use-modules (guix build utils))
- (let* ((bin (string-append %output "/bin"))
- (prog (string-append bin "/" #$name)))
- (mkdir-p bin)
- (call-with-output-file prog
- (lambda (port)
- (display #$content port)))
- (chmod prog #o755)))))
- (home-page #f)
- (synopsis #f)
- (description #f)
- (license #f)))
-
-
-(define ns1 (fmt "ns1.~a." +tld+))
-(define ns2 (fmt "ns2.~a." +tld+))
-(define ns ns1)
-(define mail (fmt "hostmaster.~a." +tld+))
-(define dkim-selector "dkimproxyout")
-(define dkim-public-key-path "/var/lib/dkimproxyout/public.key")
-
-(define dkim-name (str dkim-selector "._domainkey"))
-(define dkim-public-key
- (if (file-exists? dkim-public-key-path)
- (string-join
- (reverse
- (cdr
- (reverse
- (cdr
- (string-split (slurp dkim-public-key-path)
- #\newline)))))
- "")
- "stub-public-key-for-building"))
-
-(define ipv4-reverse-domain
- (str
- (string-join (reverse
- (string-split +ipv4+
- #\.))
- ".")
- ".in-addr.arpa"))
-
-(define ipv6-reverse-domain
- (str
- (string-join (reverse
- (map (lambda (s) (fmt "~a" s))
- (string->list
- (string-delete #\: +ipv6+))))
- ".")
- ".ip6.arpa"))
+ ((compose string-trim-right
+ serv:slurp
+ path)
+ "src/config/tld.txt"))
-(define-zone-entries tld-zone
- ("@" "" "IN" "NS" ns1)
- ("@" "" "IN" "NS" ns2)
- ("ns1" "" "IN" "A" +ipv4+)
- ("ns1" "" "IN" "AAAA" +ipv6+)
- ("ns2" "" "IN" "A" +ipv4+)
- ("ns2" "" "IN" "AAAA" +ipv6+)
- ("@" "" "IN" "A" +ipv4+)
- ("@" "" "IN" "AAAA" +ipv6+)
- ("@" "" "IN" "CAA" "0 issue \"letsencrypt.org\"")
- ("@" "" "IN" "CAA" "0 issuewild \";\"")
- ("@" "" "IN" "CAA" (fmt "0 iodef \"mailto:root@~a\"" +tld+))
+(define package-symbols
+ '())
- ("mta-sts" "" "IN" "A" +ipv4+)
- ("mta-sts" "" "IN" "AAAA" +ipv6+)
- ("_mta-sts" "" "IN" "TXT" "\"v=STSv1; id=20230314\"")
- ("@" "" "IN" "MX" (fmt "10 ~a." +tld+))
- ("_dmarc" "" "IN" "TXT" "\"v=DMARC1; p=quarantine\"")
- ("@" "" "IN" "TXT" (fmt "\"v=spf1 a:~a -all\"" +tld+))
- (dkim-name "" "IN" "TXT" (fmt "\"v=DKIM1; k=rsa; t=s; p=~a\"" dkim-public-key)))
-
-(define-zone-entries ipv4-reverse-domain-zone
- ("@" "" "IN" "PTR" (str +tld+ "."))
- ("@" "" "IN" "NS" ns1)
- ("@" "" "IN" "NS" ns2))
-
-(define-zone-entries ipv6-reverse-domain-zone
- ("@" "" "IN" "PTR" (str +tld+ "."))
- ("@" "" "IN" "NS" ns1)
- ("@" "" "IN" "NS" ns2))
-
-(define zones
- (list
- (knot-zone-configuration
- (domain +tld+)
- (semantic-checks? #t)
- (zone
- (zone-file
- (origin +tld+)
- (ns ns)
- (mail mail)
- (entries tld-zone))))
- (knot-zone-configuration
- (domain ipv4-reverse-domain)
- (semantic-checks? #t)
- (zone
- (zone-file
- (origin ipv4-reverse-domain)
- (ns ns)
- (mail mail)
- (entries ipv4-reverse-domain-zone))))
- (knot-zone-configuration
- (domain ipv6-reverse-domain)
- (semantic-checks? #t)
- (zone
- (zone-file
- (origin ipv6-reverse-domain)
- (ns ns)
- (mail mail)
- (entries ipv6-reverse-domain-zone))))))
-
-(define private-http
- '(#"-
- auth_basic "Private area";
- auth_basic_user_file /opt/secrets/htpasswd.txt;
- "#))
-
-(define cgit-nginx-config
+(define package-records
(list
- (list "fastcgi_param SCRIPT_FILENAME " cgit "/lib/cgit/cgit.cgi;")
- #"-
- fastcgi_param PATH_INFO $uri;
- fastcgi_param QUERY_STRING $args;
- fastcgi_param HTTP_HOST $server_name;
- fastcgi_pass localhost:9000;
- rewrite /git(.*) $1 break;
- "#))
+ #;
+ packages:papo.im)) ;; FIXME: move to "website" repository
(operating-system
(locale "en_GB.UTF-8")
(timezone "America/Sao_Paulo")
(host-name +tld+)
- (skeletons
- `((".profile"
- ,(plain-file
- "user-profile"
- (file "src/config/profile.sh")))))
- (users
- (append
- (list
- (user-account
- (name "git")
- (group "git")
- (system? #t)
- (comment "External SSH Git user")
- (home-directory "/srv/git")
- (create-home-directory? #f)
- (shell
- (file-append git "/bin/git-shell")))
- (user-account
- (name "deployer")
- (group "deployer")
- (system? #t)
- (comment "The account used to run deployment commands")
- (home-directory "/var/empty")
- (create-home-directory? #f)
- (shell
- (file-append shadow "/sbin/nologin")))
- (user-account
- (name "secrets-keeper")
- (group "secrets-keeper")
- (system? #t)
- (comment "The account used to manage production secrets")
- (home-directory "/var/empty")
- (create-home-directory? #f)
- (shell
- (file-append shadow "/sbin/nologin"))))
- +user-accounts+
- %base-user-accounts))
- (groups
- (append
- (list
- (user-group
- (name "git")
- (system? #t))
- (user-group
- (name "deployer")
- (system? #t))
- (user-group
- (name "become-deployer")
- (system? #t))
- (user-group
- (name "secrets-keeper")
- (system? #t))
- (user-group
- (name "become-secrets-keeper")
- (system? #t)))
- %base-groups))
- (sudoers-file
- (plain-file "sudoers" #"-
- root ALL=(ALL) ALL
- %wheel ALL= ALL
- %become-deployer ALL=(deployer) NOPASSWD: ALL
- %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= NOPASSWD: /run/current-system/profile/bin/reconfigure, /run/current-system/profile/bin/cicd
- git ALL=(deployer) NOPASSWD: /run/current-system/profile/bin/rsync, /run/current-system/profile/bin/mkdir
- "#))
- (packages
- (append
- (map
- (compose list specification->package+output symbol->string)
- '(nss-certs
- guile-heredoc
- parted
- acl
- bind:utils
- knot:tools
- file
- git
- lsof
- moreutils
- mailutils-sendmail
- curl
- make
- borg
- rsync
- sqlite
- strace
- rlwrap
- trash-cli
- tree))
- (list
- (script "gc" (file "src/scripts/gc.sh"))
- (script "cicd" (file "src/scripts/cicd.sh"))
- (script "check" (file "src/scripts/check.sh"))
- (script "backup" (file "src/scripts/backup.sh"))
- (script "deploy" (file "src/scripts/deploy.sh"))
- (script "report" (file "src/scripts/report.sh"))
- (script "cronjob" (file "src/scripts/cronjob.sh"))
- (script "reconfigure" (file "src/scripts/reconfigure.sh")))
- (list
- packages:papo.im) ;; FIXME: move to "website" repository
- %base-packages))
+ (skeletons serv:skeletons)
+ (users (append (serv:user-accounts +users+) %base-user-accounts))
+ (packages (serv:package-set package-symbols package-records))
(services
(append
(list
(service ntp-service-type)
(service dhcp-client-service-type)
- (service knot-service-type
- (knot-configuration
- (zones zones)))
- (service openssh-service-type
- (openssh-configuration
- (openssh openssh-sans-x)
- (password-authentication? #f)
- (authorized-keys +authorized-keys+)
- (extra-content #"-
- ClientAliveInterval 30
- ClientAliveCountMax 20
- MaxSessions 20
- SetEnv GIT_CONFIG_GLOBAL=/etc/gitconfig
- "#)))
- (simple-service 'extra-rottlog-rotations rottlog-service-type
- (list
- (log-rotation
- (frequency 'weekly)
- (files '("/var/log/cronjobs.log"))
- (options '("rotate 5200")))))
(service fail2ban-service-type)
- (service mcron-service-type
- (mcron-configuration
- (jobs
- (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")))))
- (service certbot-service-type
- (certbot-configuration
- (email (str "root@" +tld+))
- (certificates
- (list
- (certificate-configuration
- (domains (list +tld+))
- (deploy-hook
- (program-file
- "nginx-deploy-hook"
- #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
- (kill pid SIGHUP)))))))))
+ (service serv:binder-service-type (serv:binder-configuration (package packages:binder)))
+ (service serv:glaze-service-type (serv:glaze-configuration (package packages:glaze)))
+ (service serv:untls-service-type (serv:untls-configuration (package packages:untls)))
+ (service serv:wscat-service-type (serv:wscat-configuration (package packages:wscat)))
+ (service serv:papod-service-type (serv:papod-configuration (package packages:papod)))
+ (service openssh-service-type (q:openssh-default-configuration (serv:users->keys +users+)))
+ (service certbot-service-type (q:tld-certbot-configuration +tld+))
+ (service cgit-service-type q:cgit-pre-configuration)
+ (service serv:syskeep-service-type)
+ (service q:shadow-group-service-type)
+ (service q:dkimproxyout-service-type)
+ (service q:cyrus-sasl-service-type)
+ (service q:dovecot-service-type)
+ (service q:internet-postfix-service-type)
(service nginx-service-type
(nginx-configuration
(server-blocks
@@ -407,8 +87,8 @@
(server-name (list +tld+))
(listen '("[::]:443 ssl http2" "443 ssl http2"))
(root "/srv/www")
- (ssl-certificate (fmt "/etc/letsencrypt/live/~a/fullchain.pem" +tld+))
- (ssl-certificate-key (fmt "/etc/letsencrypt/live/~a/privkey.pem" +tld+))
+ (ssl-certificate (serv:fmt "/etc/letsencrypt/live/~a/fullchain.pem" +tld+))
+ (ssl-certificate-key (serv:fmt "/etc/letsencrypt/live/~a/privkey.pem" +tld+))
(locations
(list
(nginx-location-configuration
@@ -417,26 +97,27 @@
(list
;; FIXME: use this for blue/green deployment
#;
- (fmt "include /var/run/~a/curr.conf;~%" +tld+))))
+ (serv:fmt "include /var/run/~a/curr.conf;~%" +tld+))))
(nginx-location-configuration
(uri "/git/static/")
(body
(list
(list "alias " cgit "/share/cgit/;"))))
(nginx-location-configuration
- (uri "/git/private/")
- (body
- (append
- cgit-nginx-config
- private-http)))
- (nginx-location-configuration
(uri "/git/")
- (body cgit-nginx-config))))
+ (body
+ (list
+ (list "fastcgi_param SCRIPT_FILENAME " cgit "/lib/cgit/cgit.cgi;")
+ #"-
+ fastcgi_param PATH_INFO $uri;
+ fastcgi_param QUERY_STRING $args;
+ fastcgi_param HTTP_HOST $server_name;
+ fastcgi_pass localhost:9000;
+ rewrite /git(.*) $1 break;
+ "#)))))
(raw-content
'(#"-
- # BearSSL still doesn't do TLSv1.3, so we deem TLSv1.2 as
- # acceptable
- ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_protocols TLSv1.3;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
ssl_prefer_server_ciphers on;
gzip off; # Disable catch-all compression due to BREACH
@@ -444,35 +125,10 @@
autoindex on;
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains' always;
"#)))))))
- (service cgit-service-type queue:cgit-pre-configuration)
- (simple-service 'extra-etc-file etc-service-type
- `(("rc" ,(plain-file "rc.sh" (file "src/config/rc.sh")))
- ("known_hosts" ,(plain-file "known_hosts" (file "src/config/known_hosts.txt")))
- ("id_rsa.pub" ,(plain-file "id_rsa.pub" (file (fmt "src/keys/SSH/root@~a.id_rsa.pub.stripped" +tld+))))
- ("ssh.conf" ,(plain-file "ssh.conf" (file "src/config/ssh.conf")))
- ("init.scm" ,(plain-file "init.scm" (file "src/config/init.scm")))
- ("conf.env" ,(plain-file "conf.env" (file "src/config/conf.env")))
- ("gitconfig" ,(plain-file "gitconfig" (file "src/config/gitconfig")))))
- (service queue:shadow-group-service-type)
- (service queue:dkimproxyout-service-type)
- (service queue:cyrus-sasl-service-type)
- (service queue:dovecot-service-type)
- (service queue:internet-postfix-service-type
- (queue:postfix-configuration
- (enable-submission? #t)
- (main.cf-extra #"-
- message_size_limit = 102400000
- mailbox_size_limit = 5120000000
- "#)))
(service mail-aliases-service-type
`(("root" "andre")
("support" ,@(map s1:first +users+)))))
- (modify-services %base-services
- (rottlog-service-type config =>
- (rottlog-configuration
- (inherit config)
- (rc-file
- (file-append queue:rottlog-mailutils-sendmail "/etc/rc")))))))
+ serv:base-services))
(bootloader
(bootloader-configuration
(bootloader grub-bootloader)
diff --git a/src/scripts/backup.sh b/src/scripts/backup.sh
deleted file mode 100755
index 6a2a4ff..0000000
--- a/src/scripts/backup.sh
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- backup [-q] [-C COMMENT] [-x] [ARCHIVE_TAG]
- backup -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -q disable verbose mode, useful for batch sessions
- -C COMMENT the comment text to be attached to the archive
- -x disable checking the repository after creating the backup
- -h, --help show this message
-
- ARCHIVE_TAG the tag used to create the new
- backup (default: "manual")
-
-
- The repository is expected to have been create with:
-
- $ borg init -e repokey-blake2
-
- The following environment variables are expected to be exported:
-
- $BORG_PASSCOMMAND
- $BORG_REPO
- $BORG_REMOTE_PATH
-
- Password-less SSH access is required, usually done via adding
- /root/.ssh/id_rsa.pub to the ssh remote's
- $THE_REMOTE:.ssh/authorized_keys
-
- Root permission is also required.
-
-
- Examples:
-
- Run backup from cronjob:
-
- $ backup
-
-
- Run backup from cronjob:
-
- $ backup -q cronjob
-
-
- Create backup with a comment, a tag, and verbose mode active, and do not
- verify the repository afterwards:
-
- $ backup -xC 'The backup has a comment'
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-VERBOSE_FLAGS='--verbose --progress'
-COMMENT=' '
-CHECK=true
-while getopts 'qC:xh' flag; do
- case "$flag" in
- q)
- VERBOSE_FLAGS=''
- ;;
- C)
- COMMENT="$OPTARG"
- ;;
- x)
- CHECK=false
- ;;
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-ARCHIVE_TAG="${1:-manual}"
-
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-run() {
- STATUS=0
- set -x
- # shellcheck disable=2086
- sudo -i borg create \
- $VERBOSE_FLAGS \
- --comment "$COMMENT" \
- --stats \
- --compression lzma,9 \
- "$BORG_REPO::$(hostname)-{now}-$ARCHIVE_TAG" \
- /mnt/production/ \
- /root/ \
- /home/ \
- /etc/ \
- /var/ \
- /opt/ \
- /srv/ || STATUS=$?
- set +x
-
- if [ "$STATUS" = 0 ]; then
- return 0
- elif [ "$STATUS" = 1 ]; then
- printf 'WARNING, but no ERROR.\n' >&2
- return 0
- else
- return "$STATUS"
- fi
-}
-
-run
-
-if [ "$CHECK" = true ]; then
- # shellcheck disable=2086
- sudo -i borg check $VERBOSE_FLAGS --verify-data "$BORG_REPO"
-fi
diff --git a/src/scripts/check.sh b/src/scripts/check.sh
deleted file mode 100755
index 5c63816..0000000
--- a/src/scripts/check.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- check
- check -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -h, --help show this message
-
-
- Run system sanity checks, such as email reachability, alarms
- reachability, filesystem checks, etc.
-
-
- Examples:
-
- Just run it
-
- $ check
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-while getopts 'h' flag; do
- case "$flag" in
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-uuid() {
- od -xN20 /dev/urandom |
- head -n1 |
- awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
-}
-
-for alias in abuse admin postmaster hostmaster; do
- uuid | mail -s "\"$alias\" alias test from $(id -un)@$(hostname)" "$alias@$(hostname)"
-done
-
-
-PARTITIONS='
-/dev/vda3
-/dev/vdb1
-/dev/vdc1
-'
-set -x
-
-for part in $PARTITIONS; do
- btrfs scrub start -B "$part"
- btrfs check --force -p "$part"
-done
diff --git a/src/scripts/cicd.sh b/src/scripts/cicd.sh
deleted file mode 100755
index 58f4fce..0000000
--- a/src/scripts/cicd.sh
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- cicd [-n] NAME [SHA]
- cicd -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -n build the system, but don't switch to it (dry-run)
- -h, --help show this message
-
- NAME the name of the project
- SHA the repository SHA to checkout (default: main)
-
-
- Do a CI/CD run of the project called NAME, located at
- /srv/git/$NAME.git. If -n is given, only build, otherwise
- also do the deploy when the build is successfull.
-
- A "build" consists of:
- - doing a fresh clone of the project on a temporary directory;
- - checkout the project to version $SHA;
- - when a "manifest.scm" file exists in the root of the project,
- use it to launch a containerized Guix shell; otherwise use a
- fallback template for a containerized Guix shell;
- - build the "dev" target of the Makefile via "make dev".
-
- A "deploy" consists of:
- - copying the "description" metadata file to
- /srv/git/$NAME.git/description, in order to update the project
- repository's description;
- - upgrading the "pre-receive" Git hook, so that future runs are
- affected by it;
- - copying the "public/" directory that the "dev" target built to
- the /srv/www/s/$NAME/ directory, so that the projects "public/"
- directory is accessible via the web address
- "https://euandre.org/s/$NAME/".
-
- This command must be ran as root.
-
-
- Examples:
-
- Build and deploy the "remembering" project on the default branch:
-
- $ sudo cicd remembering
-
-
- Build the "urubu" project on a specific commit, but don't deploy:
-
- $ sudo cicd -n urubu 916dafc092f797349a54515756f2c8e477326511
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-DRY_RUN=false
-while getopts 'nh' flag; do
- case "$flag" in
- n)
- DRY_RUN=true
- ;;
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-NAME="${1:-}"
-SHA="${2:-main}"
-REPO="/srv/git/$NAME.git"
-
-if [ -z "$NAME" ]; then
- printf 'Missing NAME.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-set +eu
-# shellcheck source=/dev/null
-. /etc/rc
-set -eu
-
-
-uuid() {
- od -xN20 /dev/urandom |
- head -n1 |
- awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
-}
-
-tmpname() {
- printf '%s/uuid-tmpname with spaces.%s' "${TMPDIR:-/tmp}" "$(uuid)"
-}
-
-mkdtemp() {
- name="$(tmpname)"
- mkdir -- "$name"
- printf '%s' "$name"
-}
-
-
-TMP="$(mkdtemp)"
-trap 'rm -rf "$TMP"' EXIT
-
-
-set -x
-chown deployer:deployer "$TMP"
-cd "$TMP"
-sudo -u deployer git clone "$REPO" .
-sudo -u deployer --preserve-env=GIT_CONFIG_GLOBAL git checkout "$SHA"
-guix system describe
-
-if [ -f manifest.scm ]; then
- guix shell -Cv3 -m manifest.scm -- make dev
-else
- guix shell -Cv3 -- make dev
-fi
-
-if [ "$DRY_RUN" = false ]; then
- # COMMENT: pre-receive is always running the previous version!
- # The same is true for the reconfigure script itself.
- sudo cp description "$REPO"/description
- sudo cp aux/ci/git-pre-receive.sh "$REPO"/hooks/pre-receive
-
- sudo -u deployer rsync \
- --delete \
- --chmod=D775,F664 \
- --chown=deployer:deployer \
- --exclude 'ci/*' \
- -a \
- public/ /srv/www/s/"$NAME"/
-fi
diff --git a/src/scripts/cronjob.sh b/src/scripts/cronjob.sh
deleted file mode 100755
index 4cd456e..0000000
--- a/src/scripts/cronjob.sh
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- cronjob COMMAND...
- cronjob -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -h, --help show this message
-
- COMMAND the command to be executed
-
-
- Execute the given command, and send the output to email, with
- special treatment to the status code. It kills the job it it
- lasts more than one hour.
-
- It load the appropriate files, so that the actual cron
- declaration is smaller.
-
-
- Examples:
-
- Run a backup:
-
- $ cronjob backup -q cron
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-while getopts 'h' flag; do
- case "$flag" in
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-if [ -z "${1:-}" ]; then
- printf 'Missing COMMAND.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-set +eu
-# shellcheck source=/dev/null
-. /etc/rc
-set -eu
-
-
-
-epoch() {
- awk 'BEGIN { srand(); print(srand()); }'
-}
-
-now() {
- date '+%Y-%m-%dT%H:%M:%S%:z'
-}
-
-
-uuid() {
- od -xN20 /dev/random |
- head -n1 |
- awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
-}
-
-mkstemp() {
- name="${TMPDIR:-/tmp}/uuid-tmpname with spaces.$(uuid)"
- touch "$name"
- printf '%s' "$name"
-}
-
-pre() {
- # Same as:
- # sed -u "s|^|[$CMD]: |"
- # but the "-u" option is not POSIX
- IFS=''
- while read -r line; do
- printf '[%s]: %s\n' "$CMD" "$line"
- done
-}
-
-duration() {
- minutes=$((${1} / 60))
- seconds=$((${1} % 60))
- printf '%sm%ss' "$minutes" "$seconds"
-}
-
-
-CMD="$*"
-HOSTNAME="$(hostname)"
-FROM="cronjob@$HOSTNAME"
-TIMEOUT='10800' # three hours
-STATUS_F="$(mkstemp)"
-OUT="$(mkstemp)"
-
-email() {
- {
- cat <<-EOF
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- From: $FROM
- To: root@localhost
- Subject: (exit status: $(cat "$STATUS_F")) - $HOSTNAME: $CMD
-
- EOF
- cat "$OUT"
- } | sendmail -t -f "$FROM"
- rm -f "$OUT" "$STATUS_F"
-}
-trap email EXIT
-
-{
- cat <<-EOF
- Running commad: $CMD
- Starting at: $(now)
-
- EOF
-
- START="$(epoch)"
- STATUS=0
- timeout "$TIMEOUT" "$@" || STATUS=$?
- printf '%s' "$STATUS" > "$STATUS_F"
- END="$(epoch)"
- DURATION_SECONDS=$((END - START))
-
- cat <<-EOF
-
- Finished at: $(now)
- Duration: $(duration "$DURATION_SECONDS")
- EOF
-} 2>&1 | pre | ts '%Y-%m-%dT%H:%M:%S' | tee "$OUT" >> /var/log/cronjobs.log
diff --git a/src/scripts/deploy.sh b/src/scripts/deploy.sh
deleted file mode 100755
index dc30484..0000000
--- a/src/scripts/deploy.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- deploy
- deploy -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -h, --help show this message
-
-
- Do a blue/green deployment of the main service. It makes sure
- that the new service is up and running before shutting down the
- old one.
-
-
- Examples:
-
- Just do the deploy:
-
- $ deploy
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-while getopts 'h' flag; do
- case "$flag" in
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-echo FIXME
diff --git a/src/scripts/gc.sh b/src/scripts/gc.sh
deleted file mode 100755
index e037f3c..0000000
--- a/src/scripts/gc.sh
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- gc [TYPE]
- gc -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -h, --help show this message
-
- TYPE what to do GC on (default: all):
- - guix
- - deploy
- - trash
- - tmpdir
- - logs
-
-
- GC the server, deleting old, unusable data, in order to free
- disk space system-wide.
-
-
- Examples:
-
- Just run it, for all:
-
- $ gc
-
-
- Cleanup tmpdir:
-
- $ gc tmpdir
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-while getopts 'h' flag; do
- case "$flag" in
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-disk() {
- df -h / /mnt/backup/ |
- tail -n +2 |
- awk '{ printf "%s\t%s/%s\t%s\n", $4, $3, $2, $6 }'
-}
-
-today() {
- date '+%Y-%m-%d'
-}
-
-gc_guix() {
- sudo -i guix system delete-generations 1m
- sudo -i guix gc -d 1m
-}
-
-gc_deploy() {
- find /opt/deploy \
- ! -path /opt/deploy -prune \
- -type d \
- -not -name "$(today)*" \
- -exec rm -rvf "{}" ';'
-}
-
-gc_trash() {
- yes | sudo -i trash-empty
-}
-
-gc_tmpdir() {
- find "${TMPDIR:-/tmp}" -atime +10 -exec rm -vf "{}" ';'
-}
-
-gc_logs() {
- find /var/log/ci/ -atime +10 -exec rm -vf "{}" ';'
-}
-
-
-gc_all() {
- gc_guix
- gc_deploy
- gc_trash
- gc_tmpdir
- gc_logs
-}
-
-
-TYPE="${1:-all}"
-CMD=gc_"$TYPE"
-if ! command -v "$CMD" >/dev/null; then
- printf 'Invalid TYPE: "%s".\n\n' "$TYPE" >&2
- usage >&2
- exit 2
-fi
-
-BEFORE="$(disk)"
-set -x
-"$CMD"
-set +x
-AFTER="$(disk)"
-
-cat <<-EOF
- Disk space:
- before: $BEFORE
- after: $AFTER
-EOF
diff --git a/src/scripts/reconfigure.sh b/src/scripts/reconfigure.sh
deleted file mode 100755
index 08585b3..0000000
--- a/src/scripts/reconfigure.sh
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- reconfigure [-n] [-U] [SHA]
- reconfigure -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -n build the system, but don't switch to it (dry-run)
- -U pull the latest channels before reconfiguring
- -h, --help show this message
-
- SHA the repository SHA to checkout (default: main)
-
-
- Run a "guix system reconfigure" as root via "sudo -i". If a -U
- flag is given, perform a "guix pull" (in root profile) prior to
- the reconfigure. The user must be able to become the "deployer"
- user, either via "sudo reconfigure" or by being member of the
- "become-deployer" group.
-
-
- Examples:
-
- Reconfigure the system:
-
- $ reconfigure
-
-
- Build the system on a custom SHA, but don't switch to it:
-
- $ reconfigure -n 916dafc092f797349a54515756f2c8e477326511
-
-
- Update and upgrade:
-
- $ reconfigure -U
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-UPDATE=false
-DRY_RUN=false
-while getopts 'nUh' flag; do
- case "$flag" in
- n)
- DRY_RUN=true
- ;;
- U)
- UPDATE=true
- ;;
- h)
- usage
- help
- exit
- ;;
- *)
- usage >&2
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-# shellcheck source=/dev/null
-. /etc/conf.env
-SHA="${1:-main}"
-REPO="/srv/git/$REPO_NAME"
-NOW="$(date '+%Y-%m-%dT%H:%M:%S%:z')"
-NOW_DIR=/opt/deploy/"$NOW"
-NPROC=$(($(nproc) * 2 + 1))
-
-
-if [ "$(id -un)" != 'root' ]; then
- printf 'This script must be run as root.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-
-set +eu
-# shellcheck source=/dev/null
-. /etc/rc
-set -eu
-
-
-if [ "$UPDATE" = true ] && [ "$DRY_RUN" = false ]; then
- sudo -i guix pull -v3
-fi
-
-set -x
-sudo -u deployer git clone --depth=1 "file://$REPO" "$NOW_DIR"
-sudo -u deployer rm -f /opt/deploy/current
-sudo -u deployer ln -rs "$NOW_DIR" /opt/deploy/current
-cd /opt/deploy/current
-sudo -u deployer git fetch --depth=1 "file://$REPO" "$SHA"
-sudo -u deployer --preserve-env=GIT_CONFIG_GLOBAL git checkout "$SHA"
-guix system describe
-
-if [ "$DRY_RUN" = true ]; then
- sudo -i guix system -c$NPROC -v3 build "$PWD"/src/guix/system.scm
-else
- # COMMENT: pre-receive is always running the previous version!
- # The same is true for the reconfigure script itself.
- cp description "$REPO"/description
- cp src/ci/git-pre-receive.sh "$REPO"/hooks/pre-receive
- cp src/guix/channels.scm /etc/guix/
- cp src/guix/system.scm /etc/guix/
-
- sudo -i guix system -c$NPROC -v3 reconfigure /etc/guix/system.scm
-
- sudo -u deployer rsync \
- --delete \
- --chmod=D775,F664 \
- --chown=deployer:deployer \
- --exclude "$CI_SUFFIX/*" \
- -a \
- /run/current-system/profile/share/doc/"$NAME"/ "$HTML_OUTDIR_TOP"/
-
- ln -sf /var/log/"$NAME".log "$HTML_OUTDIR_PRIV"
-
- deploy
-fi
diff --git a/src/scripts/report.sh b/src/scripts/report.sh
deleted file mode 100755
index d9f0786..0000000
--- a/src/scripts/report.sh
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/bin/sh
-set -eu
-
-usage() {
- cat <<-'EOF'
- Usage:
- report [-C REPO] -o DIRECTORY
- report -h
- EOF
-}
-
-help() {
- cat <<-'EOF'
-
-
- Options:
- -C REPO change to REPO when doing Git operations (default: $PWD)
- -o DIRECTORY the directory where to place the generated files
- -h, --help show this message
-
-
- Gather data from Git Notes, and generate an HTML report on CI runs.
-
- Two refs with notes are expected:
- 1. refs/notes/ci-data: contains metadata abount the CI runs,
- with timestamps, filenames and exit status;
- 2. refs/notes/ci-logs: contains the content of the log.
-
- When reconstructing the CI run, the $FILENAME present in
- the refs/notes/ci-data ref names the file, and its content comes
- from refs/notes/ci-logs.
-
- On a CI run that generated the numbers from 1 to 10, for a file named
- 'my-ci-run-2020-01-01-deadbeef.log' that exited successfully, the
- expected output on the target directory "public" is:
-
- $ tree public/
- public/
- index.html
- data/
- my-ci-run-2020-01-01-deadbeef.log
- ...
- logs/
- my-ci-run-2020-01-01-deadbeef.log
- ...
-
- $ cat public/data/my-ci-run-2020-01-01-deadbeef.log
- 0 deadbeef my-ci-run-2020-01-01-deadbeef.log
-
- $ cat public/logs/my-ci-run-2020-01-01-deadbeef.log
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-
- The generated 'index.html' is a webpage with the list of all known
- CI runs, their status, a link to the commit and a link to the
- log file.
-
- To enable fetching these refs by default, do so in the git config:
-
- $ git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'
-
-
- Examples:
-
- Generate the report on the 'www' directory:
-
- $ report -o www
- EOF
-}
-
-
-for flag in "$@"; do
- case "$flag" in
- --)
- break
- ;;
- --help)
- usage
- help
- exit
- ;;
- *)
- ;;
- esac
-done
-
-REPO="$PWD"
-while getopts 'C:o:h' flag; do
- case "$flag" in
- C)
- REPO="$OPTARG"
- ;;
- o)
- OUTDIR="$OPTARG"
- ;;
- h)
- usage
- help
- exit
- ;;
- *)
- exit 2
- ;;
- esac
-done
-shift $((OPTIND - 1))
-
-if [ -z "${OUTDIR:-}" ]; then
- printf 'Missing -o OUTDIR.\n\n' >&2
- usage >&2
- exit 2
-fi
-
-if [ -r src/config/conf.env ]; then
- CONF=src/config/conf.env
-else
- CONF=/etc/conf.env
-fi
-
-# shellcheck source=/dev/null
-. "$CONF"
-
-
-esc() {
- sed \
- -e 's|&|\&amp;|g' \
- -e 's|<|\&lt;|g' \
- -e 's|>|\&gt;|g' \
- -e 's|"|\&quot;|g' \
- -e "s|'|\&#39;|g"
-}
-
-mkdir -p "$OUTDIR"
-cd "$OUTDIR"
-mkdir -p logs data
-
-for c in $(git -C "$REPO" notes list | cut -d' ' -f2); do
- git -C "$REPO" notes --ref=refs/notes/ci-data show "$c" > data/FILENAME-tmp
- FILENAME="$(grep '^filename ' data/FILENAME-tmp | cut -d' ' -f2-)"
- mv data/FILENAME-tmp data/"$FILENAME"
- git -C "$REPO" notes --ref=refs/notes/ci-logs show "$c" > logs/"$FILENAME"
-done
-
-{
- cat <<-EOF
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta name="description" content="CI logs for $NAME" />
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
- <title>$NAME - CI logs</title>
- <style>
- body {
- max-width: 800px;
- margin: 0 auto;
- }
-
- code {
- display: block;
- margin: 1em 0em 3em 3em;
- overflow: auto;
- }
-
- pre {
- display: inline;
- }
-
- ol {
- list-style-type: disc;
- }
-
- pre, code {
- background-color: #ddd;
- }
-
- @media(prefers-color-scheme: dark) {
- :root {
- color: white;
- background-color: black;
- }
-
- a {
- color: hsl(211, 100%, 60%);
- }
-
- a:visited {
- color: hsl(242, 100%, 80%);
- }
-
- pre, code {
- background-color: #222;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <h1>
- CI logs for
- <a href="$HOMEPAGE">$NAME</a>
- </h1>
- <ol>
- EOF
-
-
- PASS='&#x2705;' # ✅
- WARN='&#x1F40C;' # 🐌
- FAIL='&#x274C;' # ❌
- find data/ -type f | LANG=C.UTF-8 sort -r | while read -r f; do
- STATUS="$( grep '^status ' "$f" | cut -d' ' -f2- | esc)"
- SHA="$( grep '^sha ' "$f" | cut -d' ' -f2- | esc)"
- FILENAME="$(grep '^filename ' "$f" | cut -d' ' -f2- | esc)"
- DURATION="$(grep '^duration ' "$f" | cut -d' ' -f2- | cut -d'"' -f1 | esc)"
- MESSAGE="$({
- git -C "$REPO" log -1 --format=%B "$SHA" || {
- git fetch origin "$SHA"
- git -C "$REPO" log -1 --format=%B "$SHA"
- }
- } | esc)"
-
- if [ "$STATUS" = 0 ]; then
- if [ "$DURATION" -le 60 ]; then
- STATUS_MARKER="$PASS"
- else
- STATUS_MARKER="$WARN"
- fi
- else
- STATUS_MARKER="$FAIL"
- fi
-
- cat <<-EOF
- <li id="$FILENAME">
- <a href="#$FILENAME"><pre>#</pre></a>
- $STATUS_MARKER - <pre>${DURATION:-?}s</pre>
- <pre>(<a href="${CGIT_URL}${SHA}">commit</a>)</pre>
- <a href="logs/$FILENAME"><pre>$FILENAME</pre></a>
- <pre>(<a href="data/$FILENAME">data</a>)</pre>
- <br />
- <code><pre>$MESSAGE</pre></code>
- </li>
- EOF
- done
-
- cat <<-EOF
- </ol>
- </main>
- </body>
- </html>
- EOF
-} > index.html