Add Tribes packaging and system modules

This commit is contained in:
2026-03-30 17:54:55 +02:00
parent c0f42ef8ce
commit 7bba5c1e98
8 changed files with 855 additions and 0 deletions

View File

@@ -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`.

View 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
View 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)))))

View 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
View 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
View 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
View 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
View 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))))