You've already forked guix-tribes
Add Tribes packaging and system modules
This commit is contained in:
18
README.md
18
README.md
@@ -15,6 +15,24 @@ encryption:
|
||||
Minimal reference system using the Clevis-backed mapped-device kind and
|
||||
custom initrd.
|
||||
|
||||
It now also carries the first Tribes deployment substrate:
|
||||
|
||||
- `tribes/packages/release.scm`
|
||||
A deployment-bridge package wrapper for a prebuilt Tribes release tree.
|
||||
- `tribes/packages/source.scm`
|
||||
A real source-built Tribes package that produces a production release from a
|
||||
vendored Mix dependency tree plus local Parrhesia source.
|
||||
- `tribes/services/tribes.scm`
|
||||
Shepherd service, runtime environment wiring, and account/activation setup
|
||||
for a Tribes node.
|
||||
- `tribes/system/node.scm`
|
||||
A higher-level service bundle that wires PostgreSQL plus the Tribes service.
|
||||
- `tribes/system/installer.scm`
|
||||
Installer-facing OS constructor for NBDE-installed Tribes nodes.
|
||||
- `nbde/system/installed-base.scm`
|
||||
Shared base installed-system constructor used by both the minimal NBDE flow
|
||||
and the Tribes-specific installer path.
|
||||
|
||||
Current development status:
|
||||
|
||||
1. `luksmeta`, `tang`, and `clevis` build successfully on `pguix`.
|
||||
|
||||
56
nbde/system/installed-base.scm
Normal file
56
nbde/system/installed-base.scm
Normal file
@@ -0,0 +1,56 @@
|
||||
(define-module (nbde system installed-base)
|
||||
#:use-module (gnu)
|
||||
#:use-module (gnu services base)
|
||||
#:use-module (gnu services desktop)
|
||||
#:use-module (gnu services networking)
|
||||
#:use-module (gnu services ssh)
|
||||
#:use-module (nbde system boot-store)
|
||||
#:export (nbde-installed-operating-system))
|
||||
|
||||
(define* (nbde-installed-operating-system #:key
|
||||
host-name
|
||||
bootloader
|
||||
mapped-devices
|
||||
file-systems
|
||||
initrd
|
||||
interface
|
||||
authorized-keys-file
|
||||
(timezone "Etc/UTC")
|
||||
(locale "en_US.UTF-8")
|
||||
(kernel-arguments
|
||||
(list "console=tty0"
|
||||
"console=ttyS0,115200n8"))
|
||||
(initrd-modules
|
||||
(append '("nvme" "sd_mod" "virtio_scsi")
|
||||
%base-initrd-modules))
|
||||
(extra-services '()))
|
||||
"Return a base installed Guix system for the NBDE flow, parameterized by the
|
||||
runtime-discovered boot and filesystem values from the installer."
|
||||
(operating-system
|
||||
(host-name host-name)
|
||||
(timezone timezone)
|
||||
(locale locale)
|
||||
(keyboard-layout (keyboard-layout "us"))
|
||||
(kernel-arguments kernel-arguments)
|
||||
(initrd-modules initrd-modules)
|
||||
(initrd initrd)
|
||||
(bootloader bootloader)
|
||||
(mapped-devices mapped-devices)
|
||||
(file-systems file-systems)
|
||||
(services
|
||||
(append
|
||||
extra-services
|
||||
(list (service dhcpcd-service-type)
|
||||
(boot-store-staging-service)
|
||||
(service elogind-service-type)
|
||||
(service agetty-service-type
|
||||
(agetty-configuration
|
||||
(tty "ttyS0")
|
||||
(term "vt100")))
|
||||
(service openssh-service-type
|
||||
(openssh-configuration
|
||||
(permit-root-login 'prohibit-password)
|
||||
(authorized-keys
|
||||
(list
|
||||
(list "root" authorized-keys-file))))))
|
||||
%base-services))))
|
||||
71
tribes/packages/otp.scm
Normal file
71
tribes/packages/otp.scm
Normal file
@@ -0,0 +1,71 @@
|
||||
(define-module (tribes packages otp)
|
||||
#:use-module (guix download)
|
||||
#:use-module (guix git-download)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix utils)
|
||||
#:use-module (gnu packages)
|
||||
#:use-module (gnu packages bash)
|
||||
#:use-module (gnu packages elixir)
|
||||
#:use-module (gnu packages erlang)
|
||||
#:use-module (gnu packages perl)
|
||||
#:use-module (gnu packages version-control)
|
||||
#:export (erlang-28
|
||||
elixir-otp28
|
||||
elixir-hex-otp28))
|
||||
|
||||
(define-public erlang-28
|
||||
(package
|
||||
(inherit erlang)
|
||||
(name "erlang-28")
|
||||
(version "28.4.1")
|
||||
(source
|
||||
(origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
(url "https://github.com/erlang/otp")
|
||||
(commit (string-append "OTP-" version))))
|
||||
(file-name (git-file-name name version))
|
||||
(sha256
|
||||
(base32
|
||||
"1lsbmjfraw03d0kcdzmjdjad8b95d630d1jmg8hjklmivc13l6pa"))
|
||||
(patches (search-patches "erlang-man-path.patch"))))
|
||||
(native-inputs
|
||||
`(("perl" ,perl)
|
||||
("erlang-manpages"
|
||||
,(origin
|
||||
(method url-fetch)
|
||||
(uri (string-append
|
||||
"https://github.com/erlang/otp/releases/download"
|
||||
"/OTP-" version "/otp_doc_man_" version ".tar.gz"))
|
||||
(sha256
|
||||
(base32
|
||||
"00simi301qz3ssn71r77jmsyfz8sb61wp7k92j3gh7pq7gmmc40j"))))))))
|
||||
|
||||
(define-public elixir-otp28
|
||||
(package
|
||||
(inherit elixir)
|
||||
(name "elixir-otp28")
|
||||
(version "1.19.5")
|
||||
(source
|
||||
(origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
(url "https://github.com/elixir-lang/elixir")
|
||||
(commit (string-append "v" version))))
|
||||
(file-name (git-file-name name version))
|
||||
(sha256
|
||||
(base32
|
||||
"1i10a5d7mlcrav47k7qirqvrqn2kbl5265fbcp8fzavr86xz67m6"))
|
||||
(patches (search-patches "elixir-path-length.patch"))))
|
||||
(inputs
|
||||
`(("bash-minimal" ,bash-minimal)
|
||||
("erlang" ,erlang-28)
|
||||
("rebar3" ,rebar3)
|
||||
("git" ,git)))))
|
||||
|
||||
(define-public elixir-hex-otp28
|
||||
(package
|
||||
(inherit elixir-hex)
|
||||
(name "elixir-hex-otp28")
|
||||
(inputs
|
||||
`(("elixir" ,elixir-otp28)))))
|
||||
35
tribes/packages/release.scm
Normal file
35
tribes/packages/release.scm
Normal file
@@ -0,0 +1,35 @@
|
||||
(define-module (tribes packages release)
|
||||
#:use-module ((guix licenses) #:prefix license:)
|
||||
#:use-module (guix build-system trivial)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:export (tribes-release-package))
|
||||
|
||||
(define* (tribes-release-package source
|
||||
#:key
|
||||
(name "tribes-release")
|
||||
(version "0.0.0")
|
||||
(synopsis "Tribes release bundle")
|
||||
(description
|
||||
"Packaged Tribes release directory for deployment.")
|
||||
(home-page "https://git.teralink.net/self/tribes"))
|
||||
"Return a package that copies SOURCE, expected to be a built Tribes release
|
||||
directory, into the store unchanged. This is intended as a deployment bridge
|
||||
until the full native Guix package graph for Tribes is available."
|
||||
(package
|
||||
(name name)
|
||||
(version version)
|
||||
(source source)
|
||||
(build-system trivial-build-system)
|
||||
(arguments
|
||||
(list
|
||||
#:modules '((guix build utils))
|
||||
#:builder
|
||||
#~(begin
|
||||
(use-modules (guix build utils))
|
||||
(mkdir-p #$output)
|
||||
(copy-recursively #+source #$output #:follow-symlinks? #t))))
|
||||
(synopsis synopsis)
|
||||
(description description)
|
||||
(home-page home-page)
|
||||
(license license:asl2.0)))
|
||||
252
tribes/packages/source.scm
Normal file
252
tribes/packages/source.scm
Normal file
@@ -0,0 +1,252 @@
|
||||
(define-module (tribes packages source)
|
||||
#:use-module ((guix licenses) #:prefix license:)
|
||||
#:use-module (guix build-system trivial)
|
||||
#:use-module (guix git-download)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix utils)
|
||||
#:use-module (gnu packages admin)
|
||||
#:use-module (gnu packages autotools)
|
||||
#:use-module (gnu packages bash)
|
||||
#:use-module (gnu packages base)
|
||||
#:use-module (gnu packages commencement)
|
||||
#:use-module (gnu packages erlang)
|
||||
#:use-module (gnu packages gawk)
|
||||
#:use-module (gnu packages linux)
|
||||
#:use-module (gnu packages m4)
|
||||
#:use-module (gnu packages nss)
|
||||
#:use-module (gnu packages perl)
|
||||
#:use-module (gnu packages pkg-config)
|
||||
#:use-module (gnu packages version-control)
|
||||
#:use-module (tribes packages otp)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-13)
|
||||
#:export (tribes-source-package
|
||||
tribes-source-directory->local-file))
|
||||
|
||||
(define %excluded-root-basenames
|
||||
'(".cache"
|
||||
".claude"
|
||||
".direnv"
|
||||
".elixir_ls"
|
||||
".git"
|
||||
".hex"
|
||||
".home"
|
||||
".mix-home"
|
||||
".pre-commit-config.yaml"
|
||||
"_build"
|
||||
"deps"
|
||||
"erl_crash.dump"
|
||||
"node_modules"
|
||||
"result"))
|
||||
|
||||
(define (root-artifact-path? root file entry)
|
||||
(let ((entry-path (string-append root "/" entry)))
|
||||
(or (string=? file entry-path)
|
||||
(string-prefix? (string-append entry-path "/") file))))
|
||||
|
||||
(define (transient-source-file? root file)
|
||||
(let ((base (basename file)))
|
||||
(or (any (lambda (entry)
|
||||
(root-artifact-path? root file entry))
|
||||
%excluded-root-basenames)
|
||||
(root-artifact-path? root file ".env")
|
||||
(string-prefix? ".devenv" base)
|
||||
(string=? base ".env")
|
||||
(string-suffix? ".log" base)
|
||||
(string-suffix? ".tsbuildinfo" base)
|
||||
(string-suffix? ".db" base)
|
||||
(string-suffix? ".db-shm" base)
|
||||
(string-suffix? ".db-wal" base))))
|
||||
|
||||
(define (tribes-source-select? root file stat)
|
||||
(or (string=? file root)
|
||||
(not (transient-source-file? root file))))
|
||||
|
||||
(define (tribes-source-directory->local-file directory)
|
||||
"Return DIRECTORY as a recursively copied local-file, excluding transient
|
||||
build artifacts and, when available, anything not tracked in the enclosing Git
|
||||
checkout."
|
||||
(let ((git-select? (git-predicate directory)))
|
||||
(local-file directory
|
||||
#:recursive? #t
|
||||
#:select?
|
||||
(if git-select?
|
||||
(lambda (file stat)
|
||||
(and (git-select? file stat)
|
||||
(tribes-source-select? directory file stat)))
|
||||
(lambda (file stat)
|
||||
(tribes-source-select? directory file stat))))))
|
||||
|
||||
(define* (tribes-source-package source
|
||||
mix-deps
|
||||
parrhesia-source
|
||||
#:key
|
||||
(name "tribes")
|
||||
(version "0.2.0")
|
||||
(home-page "https://git.teralink.net/self/tribes")
|
||||
(synopsis "Tribes social app")
|
||||
(description
|
||||
"Tribes social application built from source as a
|
||||
production Elixir release using a vendored Mix dependency tree."))
|
||||
"Return a Guix package that builds a production Tribes release from SOURCE,
|
||||
using MIX-DEPS as the pre-fetched Mix dependency tree and PARRHESIA-SOURCE as
|
||||
the local Parrhesia path dependency."
|
||||
(package
|
||||
(name name)
|
||||
(version version)
|
||||
(source source)
|
||||
(build-system trivial-build-system)
|
||||
(native-inputs
|
||||
(list autoconf
|
||||
autoconf-wrapper
|
||||
automake
|
||||
bash-minimal
|
||||
coreutils
|
||||
elixir-otp28
|
||||
elixir-hex-otp28
|
||||
findutils
|
||||
gcc-toolchain
|
||||
gawk
|
||||
git-minimal
|
||||
grep
|
||||
gnu-make
|
||||
libtool
|
||||
linux-libre-headers
|
||||
m4
|
||||
nss-certs
|
||||
perl
|
||||
pkg-config
|
||||
sed
|
||||
rebar3))
|
||||
(arguments
|
||||
(list
|
||||
#:modules '((guix build utils)
|
||||
(ice-9 ftw)
|
||||
(ice-9 textual-ports)
|
||||
(srfi srfi-1))
|
||||
#:builder
|
||||
#~(begin
|
||||
(use-modules (guix build utils)
|
||||
(ice-9 ftw)
|
||||
(ice-9 textual-ports)
|
||||
(srfi srfi-1))
|
||||
|
||||
(define out #$output)
|
||||
(define work (string-append (getcwd) "/build"))
|
||||
(define app-dir (string-append work "/tribes"))
|
||||
(define parrhesia-dir (string-append work "/parrhesia"))
|
||||
(define deps-dir (string-append app-dir "/deps"))
|
||||
(define cert-file
|
||||
#$(file-append nss-certs "/etc/ssl/certs/ca-certificates.crt"))
|
||||
(define hex-lib-dir
|
||||
#$(file-append elixir-hex-otp28
|
||||
"/lib/elixir/"
|
||||
(version-major+minor
|
||||
(package-version elixir-otp28))))
|
||||
(define kernel-headers-dir
|
||||
#$(file-append linux-libre-headers "/include"))
|
||||
(define sh-bin
|
||||
#$(file-append bash-minimal "/bin/sh"))
|
||||
(define path
|
||||
(string-join
|
||||
(list #$(file-append elixir-otp28 "/bin")
|
||||
#$(file-append elixir-hex-otp28 "/bin")
|
||||
#$(file-append rebar3 "/bin")
|
||||
#$(file-append gcc-toolchain "/bin")
|
||||
#$(file-append gnu-make "/bin")
|
||||
#$(file-append autoconf-wrapper "/bin")
|
||||
#$(file-append autoconf "/bin")
|
||||
#$(file-append automake "/bin")
|
||||
#$(file-append bash-minimal "/bin")
|
||||
#$(file-append coreutils "/bin")
|
||||
#$(file-append findutils "/bin")
|
||||
#$(file-append libtool "/bin")
|
||||
#$(file-append gawk "/bin")
|
||||
#$(file-append grep "/bin")
|
||||
#$(file-append m4 "/bin")
|
||||
#$(file-append perl "/bin")
|
||||
#$(file-append pkg-config "/bin")
|
||||
#$(file-append sed "/bin")
|
||||
#$(file-append git-minimal "/bin")
|
||||
(or (getenv "PATH") ""))
|
||||
":"))
|
||||
|
||||
(mkdir-p work)
|
||||
(copy-recursively #+source app-dir #:follow-symlinks? #t)
|
||||
(copy-recursively #+parrhesia-source parrhesia-dir #:follow-symlinks? #t)
|
||||
(copy-recursively #+mix-deps deps-dir #:follow-symlinks? #t)
|
||||
(invoke #$(file-append coreutils "/bin/chmod")
|
||||
"-R" "u+w"
|
||||
app-dir
|
||||
parrhesia-dir
|
||||
deps-dir)
|
||||
|
||||
(substitute* (string-append app-dir "/mix.exs")
|
||||
(("\\{:parrhesia, github: \"serpent213/parrhesia\", branch: \"master\"\\}")
|
||||
"{:parrhesia, path: \"../parrhesia\"}"))
|
||||
(let ((mix-lock (string-append app-dir "/mix.lock")))
|
||||
(when (file-exists? mix-lock)
|
||||
(substitute* mix-lock
|
||||
(("^ \"parrhesia\": \\{:git, \"https://github\\.com/serpent213/parrhesia\\.git\", \".*\", \\[branch: \"master\"\\]\\},$")
|
||||
""))))
|
||||
(let ((libsecp-makefile
|
||||
(string-append deps-dir "/lib_secp256k1/Makefile")))
|
||||
(when (file-exists? libsecp-makefile)
|
||||
(substitute* libsecp-makefile
|
||||
(("\\./autogen\\.sh")
|
||||
(string-append sh-bin " ./autogen.sh")))))
|
||||
|
||||
(setenv "PATH" path)
|
||||
(setenv "HOME" (string-append app-dir "/.home"))
|
||||
(setenv "MIX_HOME" (string-append app-dir "/.mix-home"))
|
||||
(setenv "HEX_HOME" (string-append app-dir "/.hex"))
|
||||
(setenv "XDG_CACHE_HOME" (string-append app-dir "/.cache"))
|
||||
(let ((existing-elixir-libs (getenv "GUIX_ELIXIR_LIBS")))
|
||||
(setenv "GUIX_ELIXIR_LIBS"
|
||||
(if existing-elixir-libs
|
||||
(string-append hex-lib-dir ":" existing-elixir-libs)
|
||||
hex-lib-dir)))
|
||||
(setenv "MIX_ENV" "prod")
|
||||
(setenv "MIX_REBAR3" #$(file-append rebar3 "/bin/rebar3"))
|
||||
(setenv "SSL_CERT_FILE" cert-file)
|
||||
(let ((existing-cpath (getenv "CPATH")))
|
||||
(setenv "CPATH"
|
||||
(if existing-cpath
|
||||
(string-append kernel-headers-dir ":" existing-cpath)
|
||||
kernel-headers-dir)))
|
||||
(let ((existing-c-include-path (getenv "C_INCLUDE_PATH")))
|
||||
(setenv "C_INCLUDE_PATH"
|
||||
(if existing-c-include-path
|
||||
(string-append kernel-headers-dir ":" existing-c-include-path)
|
||||
kernel-headers-dir)))
|
||||
(setenv "CC" #$(file-append gcc-toolchain "/bin/gcc"))
|
||||
(setenv "CXX" #$(file-append gcc-toolchain "/bin/g++"))
|
||||
(mkdir-p (getenv "HOME"))
|
||||
(mkdir-p (getenv "MIX_HOME"))
|
||||
(mkdir-p (getenv "HEX_HOME"))
|
||||
(mkdir-p (getenv "XDG_CACHE_HOME"))
|
||||
|
||||
(with-directory-excursion app-dir
|
||||
;; Absinthe has been the last fragile dependency in Guix builds so
|
||||
;; far. Compile its immediate deps first, then compile Absinthe in
|
||||
;; its own pass before compiling the remaining dependency graph.
|
||||
(invoke "mix" "deps.compile" "nimble_parsec" "telemetry" "decimal")
|
||||
(let ((existing-erl-flags (getenv "ERL_FLAGS")))
|
||||
;; Keep the scheduler count pinned while compiling Absinthe so
|
||||
;; toolchain-sensitive ordering issues stay deterministic.
|
||||
(setenv "ERL_FLAGS"
|
||||
(if existing-erl-flags
|
||||
(string-append existing-erl-flags " +S 1:1")
|
||||
"+S 1:1"))
|
||||
(invoke "mix" "deps.compile" "absinthe" "--force")
|
||||
(if existing-erl-flags
|
||||
(setenv "ERL_FLAGS" existing-erl-flags)
|
||||
(unsetenv "ERL_FLAGS")))
|
||||
(invoke "mix" "deps.compile")
|
||||
(invoke "mix" "compile")
|
||||
(invoke "mix" "release" "--path" out)))))
|
||||
(home-page home-page)
|
||||
(synopsis synopsis)
|
||||
(description description)
|
||||
(license license:asl2.0)))
|
||||
272
tribes/services/tribes.scm
Normal file
272
tribes/services/tribes.scm
Normal file
@@ -0,0 +1,272 @@
|
||||
(define-module (tribes services tribes)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services base)
|
||||
#:use-module (gnu services databases)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu packages admin)
|
||||
#:use-module (gnu system shadow)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix records)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (srfi srfi-13)
|
||||
#:export (tribes-configuration
|
||||
tribes-configuration?
|
||||
tribes-configuration-package
|
||||
tribes-configuration-user
|
||||
tribes-configuration-group
|
||||
tribes-configuration-working-directory
|
||||
tribes-configuration-plugin-directory
|
||||
tribes-configuration-host
|
||||
tribes-configuration-scheme
|
||||
tribes-configuration-port
|
||||
tribes-configuration-relay-url
|
||||
tribes-configuration-host-manifest
|
||||
tribes-configuration-admin-pubkeys
|
||||
tribes-configuration-sync-overlap-seconds
|
||||
tribes-configuration-database-user
|
||||
tribes-configuration-database-name
|
||||
tribes-configuration-parrhesia-database-name
|
||||
tribes-configuration-database-host
|
||||
tribes-configuration-secret-key-base-file
|
||||
tribes-configuration-token-signing-secret-file
|
||||
tribes-configuration-dns-cluster-query
|
||||
tribes-configuration-extra-environment-variables
|
||||
tribes-configuration-log-file
|
||||
tribes-service-type))
|
||||
|
||||
(define-record-type* <tribes-configuration>
|
||||
tribes-configuration make-tribes-configuration
|
||||
tribes-configuration?
|
||||
(package tribes-configuration-package
|
||||
(default #f))
|
||||
(user tribes-configuration-user
|
||||
(default "tribes"))
|
||||
(group tribes-configuration-group
|
||||
(default "tribes"))
|
||||
(working-directory tribes-configuration-working-directory
|
||||
(default "/var/lib/tribes"))
|
||||
(plugin-directory tribes-configuration-plugin-directory
|
||||
(default "/var/lib/tribes/plugins"))
|
||||
(host tribes-configuration-host
|
||||
(default "localhost"))
|
||||
(scheme tribes-configuration-scheme
|
||||
(default "http"))
|
||||
(port tribes-configuration-port
|
||||
(default 4000))
|
||||
(relay-url tribes-configuration-relay-url
|
||||
(default #f))
|
||||
(host-manifest tribes-configuration-host-manifest
|
||||
(default #f))
|
||||
(admin-pubkeys tribes-configuration-admin-pubkeys
|
||||
(default '()))
|
||||
(sync-overlap-seconds tribes-configuration-sync-overlap-seconds
|
||||
(default 300))
|
||||
(database-user tribes-configuration-database-user
|
||||
(default "tribes"))
|
||||
(database-name tribes-configuration-database-name
|
||||
(default "tribes"))
|
||||
(parrhesia-database-name tribes-configuration-parrhesia-database-name
|
||||
(default "parrhesia"))
|
||||
(database-host tribes-configuration-database-host
|
||||
(default "/var/run/postgresql"))
|
||||
(secret-key-base-file tribes-configuration-secret-key-base-file
|
||||
(default "/var/lib/tribes/secrets/secret_key_base"))
|
||||
(token-signing-secret-file tribes-configuration-token-signing-secret-file
|
||||
(default "/var/lib/tribes/secrets/token_signing_secret"))
|
||||
(dns-cluster-query tribes-configuration-dns-cluster-query
|
||||
(default #f))
|
||||
(extra-environment-variables tribes-configuration-extra-environment-variables
|
||||
(default '()))
|
||||
(log-file tribes-configuration-log-file
|
||||
(default "/var/log/tribes/tribes.log")))
|
||||
|
||||
(define (tribes-accounts config)
|
||||
(list
|
||||
(user-group
|
||||
(name (tribes-configuration-group config))
|
||||
(system? #t))
|
||||
(user-account
|
||||
(name (tribes-configuration-user config))
|
||||
(group (tribes-configuration-group config))
|
||||
(system? #t)
|
||||
(comment "Tribes service user")
|
||||
(home-directory (tribes-configuration-working-directory config))
|
||||
(shell (file-append shadow "/sbin/nologin")))))
|
||||
|
||||
(define (tribes-relay-url config)
|
||||
(or (tribes-configuration-relay-url config)
|
||||
(let* ((scheme (tribes-configuration-scheme config))
|
||||
(host (tribes-configuration-host config))
|
||||
(port (tribes-configuration-port config))
|
||||
(ws-scheme (if (string=? scheme "https") "wss" "ws"))
|
||||
(default-port?
|
||||
(or (and (string=? scheme "https") (= port 443))
|
||||
(and (string=? scheme "http") (= port 80)))))
|
||||
(if default-port?
|
||||
(string-append ws-scheme "://" host "/nostr/relay")
|
||||
(string-append ws-scheme "://" host ":" (number->string port)
|
||||
"/nostr/relay")))))
|
||||
|
||||
(define (tribes-database-url config database-name)
|
||||
(string-append "ecto://"
|
||||
(tribes-configuration-database-user config)
|
||||
"@/"
|
||||
database-name
|
||||
"?host="
|
||||
(tribes-configuration-database-host config)))
|
||||
|
||||
(define (tribes-launcher config command args)
|
||||
(define package
|
||||
(tribes-configuration-package config))
|
||||
(define env-setters
|
||||
(append
|
||||
(list
|
||||
#~(setenv "HOME" #$(tribes-configuration-working-directory config))
|
||||
#~(setenv "PHX_SERVER" "true")
|
||||
#~(setenv "PORT" #$(number->string (tribes-configuration-port config)))
|
||||
#~(setenv "PHX_HOST" #$(tribes-configuration-host config))
|
||||
#~(setenv "DATABASE_URL"
|
||||
#$(tribes-database-url
|
||||
config
|
||||
(tribes-configuration-database-name config)))
|
||||
#~(setenv "PARRHESIA_DATABASE_URL"
|
||||
#$(tribes-database-url
|
||||
config
|
||||
(tribes-configuration-parrhesia-database-name config)))
|
||||
#~(setenv "PARRHESIA_RELAY_URL" #$(tribes-relay-url config))
|
||||
#~(setenv "TRIBES_PLUGIN_DIR" #$(tribes-configuration-plugin-directory config))
|
||||
#~(setenv "TRIBES_SYNC_OVERLAP_SECONDS"
|
||||
#$(number->string
|
||||
(tribes-configuration-sync-overlap-seconds config)))
|
||||
#~(setenv "TRIBES_ADMIN_PUBKEYS"
|
||||
#$(string-join
|
||||
(tribes-configuration-admin-pubkeys config)
|
||||
","))
|
||||
#~(setenv "SSL_CERT_DIR" "/etc/ssl/certs")
|
||||
#~(setenv "SSL_CERT_FILE" "/etc/ssl/certs/ca-certificates.crt"))
|
||||
(if (tribes-configuration-host-manifest config)
|
||||
(list #~(setenv "TRIBES_HOST_MANIFEST"
|
||||
#$(tribes-configuration-host-manifest config)))
|
||||
'())
|
||||
(if (tribes-configuration-dns-cluster-query config)
|
||||
(list #~(setenv "DNS_CLUSTER_QUERY"
|
||||
#$(tribes-configuration-dns-cluster-query config)))
|
||||
'())
|
||||
(map (lambda (entry)
|
||||
#~(let* ((entry #$entry)
|
||||
(parts (string-split entry #\=))
|
||||
(name (car parts))
|
||||
(value (string-join (cdr parts) "=")))
|
||||
(setenv name value)))
|
||||
(tribes-configuration-extra-environment-variables config))))
|
||||
(program-file
|
||||
(string-append "tribes-" command)
|
||||
#~(begin
|
||||
(use-modules (ice-9 textual-ports)
|
||||
(srfi srfi-13))
|
||||
|
||||
(define (read-secret path)
|
||||
(string-trim-right (call-with-input-file path get-string-all)))
|
||||
|
||||
(define secret-key-file
|
||||
#$(tribes-configuration-secret-key-base-file config))
|
||||
(define token-file
|
||||
#$(tribes-configuration-token-signing-secret-file config))
|
||||
|
||||
(unless (file-exists? secret-key-file)
|
||||
(format (current-error-port)
|
||||
"missing Tribes secret file: ~a~%"
|
||||
secret-key-file)
|
||||
(exit 1))
|
||||
|
||||
(unless (file-exists? token-file)
|
||||
(format (current-error-port)
|
||||
"missing Tribes token-signing secret file: ~a~%"
|
||||
token-file)
|
||||
(exit 1))
|
||||
|
||||
(setenv "SECRET_KEY_BASE" (read-secret secret-key-file))
|
||||
(setenv "TOKEN_SIGNING_SECRET" (read-secret token-file))
|
||||
#$@env-setters
|
||||
(apply execl
|
||||
#$(file-append package "/bin/tribes")
|
||||
"tribes"
|
||||
(cons #$command '#$args)))))
|
||||
|
||||
(define (tribes-activation config)
|
||||
#~(begin
|
||||
(use-modules (guix build utils)
|
||||
(ice-9 match)
|
||||
(srfi srfi-1))
|
||||
(let* ((user (getpwnam #$(tribes-configuration-user config)))
|
||||
(uid (passwd:uid user))
|
||||
(gid (passwd:gid user))
|
||||
(dirs (list #$(tribes-configuration-working-directory config)
|
||||
#$(tribes-configuration-plugin-directory config)
|
||||
(dirname #$(tribes-configuration-log-file config))
|
||||
(dirname #$(tribes-configuration-secret-key-base-file config))
|
||||
(dirname #$(tribes-configuration-token-signing-secret-file config)))))
|
||||
(for-each
|
||||
(lambda (dir)
|
||||
(mkdir-p dir)
|
||||
(chown dir uid gid))
|
||||
dirs))))
|
||||
|
||||
(define (tribes-migrations-shepherd-service config)
|
||||
(let ((launcher (tribes-launcher
|
||||
config
|
||||
"eval"
|
||||
'("Tribes.Release.migrate_with_storage_up()"))))
|
||||
(list
|
||||
(shepherd-service
|
||||
(documentation "Run Tribes database migrations.")
|
||||
(provision '(tribes-migrations))
|
||||
(requirement '(postgres user-processes))
|
||||
(one-shot? #t)
|
||||
(start
|
||||
#~(lambda _
|
||||
(zero? (spawn-command
|
||||
(list #$launcher)
|
||||
#:user #$(tribes-configuration-user config)
|
||||
#:group #$(tribes-configuration-group config)))))
|
||||
(respawn? #f)))))
|
||||
|
||||
(define (tribes-shepherd-service config)
|
||||
(let ((launcher (tribes-launcher config "start" '())))
|
||||
(list
|
||||
(shepherd-service
|
||||
(documentation "Run the Tribes application service.")
|
||||
(provision '(tribes))
|
||||
(requirement '(tribes-migrations networking user-processes))
|
||||
(start
|
||||
#~(make-forkexec-constructor
|
||||
(list #$launcher)
|
||||
#:user #$(tribes-configuration-user config)
|
||||
#:group #$(tribes-configuration-group config)
|
||||
#:log-file #$(tribes-configuration-log-file config)))
|
||||
(stop #~(make-kill-destructor))
|
||||
(respawn? #f)))))
|
||||
|
||||
(define (tribes-profile-packages config)
|
||||
(match (tribes-configuration-package config)
|
||||
(#f '())
|
||||
(package (list package))))
|
||||
|
||||
(define tribes-service-type
|
||||
(service-type
|
||||
(name 'tribes)
|
||||
(extensions
|
||||
(list (service-extension account-service-type
|
||||
tribes-accounts)
|
||||
(service-extension activation-service-type
|
||||
tribes-activation)
|
||||
(service-extension shepherd-root-service-type
|
||||
tribes-migrations-shepherd-service)
|
||||
(service-extension shepherd-root-service-type
|
||||
tribes-shepherd-service)
|
||||
(service-extension profile-service-type
|
||||
tribes-profile-packages)))
|
||||
(default-value (tribes-configuration))
|
||||
(description
|
||||
"Run a Tribes release with PostgreSQL-backed storage, Parrhesia, and
|
||||
cluster runtime configuration sourced from files and service settings.")))
|
||||
114
tribes/system/installer.scm
Normal file
114
tribes/system/installer.scm
Normal file
@@ -0,0 +1,114 @@
|
||||
(define-module (tribes system installer)
|
||||
#:use-module (gnu packages databases)
|
||||
#:use-module (gnu services databases)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (nbde system installed-base)
|
||||
#:use-module (tribes packages release)
|
||||
#:use-module (tribes packages source)
|
||||
#:use-module (tribes services tribes)
|
||||
#:use-module (tribes system node)
|
||||
#:use-module (srfi srfi-13)
|
||||
#:export (tribes-installer-operating-system))
|
||||
|
||||
(define (getenv/default name default)
|
||||
(or (getenv name) default))
|
||||
|
||||
(define (getenv/integer name default)
|
||||
(let ((value (getenv name)))
|
||||
(if value
|
||||
(or (string->number value)
|
||||
(error "invalid integer environment variable" name value))
|
||||
default)))
|
||||
|
||||
(define (comma-list value)
|
||||
(if (or (not value) (string-null? value))
|
||||
'()
|
||||
(map string-trim-both
|
||||
(filter (lambda (item) (not (string-null? item)))
|
||||
(string-split value #\,)))))
|
||||
|
||||
(define* (tribes-installer-operating-system #:key
|
||||
host-name
|
||||
bootloader
|
||||
mapped-devices
|
||||
file-systems
|
||||
initrd
|
||||
interface
|
||||
authorized-keys-file)
|
||||
"Return an installed NBDE operating-system extended with PostgreSQL and the
|
||||
Tribes service. The package source is provided through
|
||||
TRIBES_RELEASE_DIRECTORY and wrapped as a Guix package at evaluation time."
|
||||
(let* ((release-directory
|
||||
(getenv "TRIBES_RELEASE_DIRECTORY"))
|
||||
(source-directory (getenv "TRIBES_SOURCE_DIRECTORY"))
|
||||
(mix-deps-directory (getenv "TRIBES_MIX_DEPS_DIRECTORY"))
|
||||
(parrhesia-directory (getenv "TRIBES_PARRHESIA_DIRECTORY"))
|
||||
(service-user (getenv/default "TRIBES_SERVICE_USER" "tribes"))
|
||||
(service-group (getenv/default "TRIBES_SERVICE_GROUP" service-user))
|
||||
(database-user (getenv/default "TRIBES_DATABASE_USER" service-user))
|
||||
(package
|
||||
(cond
|
||||
((and source-directory mix-deps-directory parrhesia-directory)
|
||||
(tribes-source-package
|
||||
(tribes-source-directory->local-file source-directory)
|
||||
(tribes-source-directory->local-file mix-deps-directory)
|
||||
(tribes-source-directory->local-file parrhesia-directory)
|
||||
#:version (getenv/default "TRIBES_RELEASE_VERSION" "dev")))
|
||||
(release-directory
|
||||
(tribes-release-package
|
||||
(local-file release-directory #:recursive? #t)
|
||||
#:version (getenv/default "TRIBES_RELEASE_VERSION" "dev")))
|
||||
(else
|
||||
(error "missing Tribes package input; set TRIBES_RELEASE_DIRECTORY or "
|
||||
"TRIBES_SOURCE_DIRECTORY, TRIBES_MIX_DEPS_DIRECTORY, and "
|
||||
"TRIBES_PARRHESIA_DIRECTORY"))))
|
||||
(tribes-config
|
||||
(tribes-configuration
|
||||
(package package)
|
||||
(user service-user)
|
||||
(group service-group)
|
||||
(working-directory
|
||||
(getenv/default "TRIBES_WORKING_DIRECTORY" "/var/lib/tribes"))
|
||||
(plugin-directory
|
||||
(getenv/default "TRIBES_PLUGIN_DIRECTORY" "/var/lib/tribes/plugins"))
|
||||
(host (getenv/default "TRIBES_PUBLIC_HOST" host-name))
|
||||
(scheme (getenv/default "TRIBES_SCHEME" "http"))
|
||||
(port (getenv/integer "TRIBES_HTTP_PORT" 4000))
|
||||
(relay-url (getenv "TRIBES_RELAY_URL"))
|
||||
(host-manifest (getenv "TRIBES_HOST_MANIFEST"))
|
||||
(admin-pubkeys
|
||||
(comma-list (getenv "TRIBES_ADMIN_PUBKEYS")))
|
||||
(sync-overlap-seconds
|
||||
(getenv/integer "TRIBES_SYNC_OVERLAP_SECONDS" 300))
|
||||
(database-user database-user)
|
||||
(database-name
|
||||
(getenv/default "TRIBES_DATABASE_NAME" "tribes"))
|
||||
(parrhesia-database-name
|
||||
(getenv/default "TRIBES_PARRHESIA_DATABASE_NAME" "parrhesia"))
|
||||
(database-host
|
||||
(getenv/default "TRIBES_DATABASE_HOST" "/var/run/postgresql"))
|
||||
(secret-key-base-file
|
||||
(getenv/default "TRIBES_SECRET_KEY_BASE_FILE"
|
||||
"/var/lib/tribes/secrets/secret_key_base"))
|
||||
(token-signing-secret-file
|
||||
(getenv/default "TRIBES_TOKEN_SIGNING_SECRET_FILE"
|
||||
"/var/lib/tribes/secrets/token_signing_secret"))
|
||||
(dns-cluster-query (getenv "TRIBES_DNS_CLUSTER_QUERY"))
|
||||
(extra-environment-variables
|
||||
(comma-list (getenv "TRIBES_EXTRA_ENV")))
|
||||
(log-file
|
||||
(getenv/default "TRIBES_LOG_FILE" "/var/log/tribes/tribes.log"))))
|
||||
(node-config
|
||||
(tribes-node-configuration
|
||||
(postgresql (postgresql-configuration
|
||||
(postgresql postgresql)))
|
||||
(tribes tribes-config))))
|
||||
(nbde-installed-operating-system
|
||||
#:host-name host-name
|
||||
#:bootloader bootloader
|
||||
#:mapped-devices mapped-devices
|
||||
#:file-systems file-systems
|
||||
#:initrd initrd
|
||||
#:interface interface
|
||||
#:authorized-keys-file authorized-keys-file
|
||||
#:extra-services (tribes-node-services node-config))))
|
||||
37
tribes/system/node.scm
Normal file
37
tribes/system/node.scm
Normal file
@@ -0,0 +1,37 @@
|
||||
(define-module (tribes system node)
|
||||
#:use-module (gnu packages databases)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services databases)
|
||||
#:use-module (guix records)
|
||||
#:use-module (tribes services tribes)
|
||||
#:export (tribes-node-configuration
|
||||
tribes-node-configuration?
|
||||
tribes-node-configuration-postgresql
|
||||
tribes-node-configuration-tribes
|
||||
tribes-node-services))
|
||||
|
||||
(define-record-type* <tribes-node-configuration>
|
||||
tribes-node-configuration make-tribes-node-configuration
|
||||
tribes-node-configuration?
|
||||
(postgresql tribes-node-configuration-postgresql
|
||||
(default (postgresql-configuration
|
||||
(postgresql postgresql))))
|
||||
(tribes tribes-node-configuration-tribes
|
||||
(default (tribes-configuration))))
|
||||
|
||||
(define (tribes-node-postgresql-roles config)
|
||||
(let ((tribes (tribes-node-configuration-tribes config)))
|
||||
(list
|
||||
(postgresql-role
|
||||
(name (tribes-configuration-database-user tribes))
|
||||
(permissions '(createdb login))))))
|
||||
|
||||
(define (tribes-node-services config)
|
||||
(list
|
||||
(service postgresql-service-type
|
||||
(tribes-node-configuration-postgresql config))
|
||||
(simple-service 'tribes-postgresql-roles
|
||||
postgresql-role-service-type
|
||||
(tribes-node-postgresql-roles config))
|
||||
(service tribes-service-type
|
||||
(tribes-node-configuration-tribes config))))
|
||||
Reference in New Issue
Block a user