You've already forked guix-tribes
Compare commits
213 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
fad91de317
|
|||
|
2e0a57b2f3
|
|||
|
5619314fc3
|
|||
|
d122d5ecfc
|
|||
|
50f9f561f5
|
|||
|
3cdc88961b
|
|||
|
4626df8b5d
|
|||
|
f4f14fb86d
|
|||
|
b8f2ee5823
|
|||
|
01f9532aa2
|
|||
|
395ac9258b
|
|||
|
193c28aa2c
|
|||
|
8a66dd853d
|
|||
|
5d2b8a7b90
|
|||
|
9b90630484
|
|||
|
adfcf09426
|
|||
|
937b9aa18d
|
|||
|
5abdfc8fcc
|
|||
|
bc8ff14569
|
|||
|
ba211e1d18
|
|||
|
b08420710a
|
|||
|
061ea3da52
|
|||
|
07f831a909
|
|||
|
0bbeed9df9
|
|||
|
dfc6f3ebb3
|
|||
|
b522f743aa
|
|||
|
e62a3d30b1
|
|||
|
2ec1a43460
|
|||
|
b85de2ba63
|
|||
|
9269bb0b13
|
|||
|
324091a366
|
|||
|
1fe532e294
|
|||
|
46991aa6c8
|
|||
|
6666432cbc
|
|||
|
149bf4e921
|
|||
|
41866bf0ff
|
|||
|
35e8044ae6
|
|||
|
0957da2e5a
|
|||
|
8978b62a93
|
|||
|
77d9717707
|
|||
|
05f7ec5b60
|
|||
|
b45ae0c87b
|
|||
|
db6ed5b6dd
|
|||
|
54f23bc863
|
|||
|
cd0297edaf
|
|||
|
94ca870450
|
|||
|
f81eb2e12e
|
|||
|
31e622899b
|
|||
|
168e79994e
|
|||
|
d3e0daf74e
|
|||
|
2ea4cae872
|
|||
|
635d5b24a2
|
|||
|
cacb8c56f9
|
|||
|
d20a5ec923
|
|||
|
f25b2d9254
|
|||
|
755d0bec32
|
|||
|
79ec9e572d
|
|||
|
af6bcb4b77
|
|||
|
722fff45ce
|
|||
|
d1f82d27e8
|
|||
|
39da8d4d32
|
|||
|
e40f2f4d8f
|
|||
|
700886b53a
|
|||
|
2ea3cfd211
|
|||
|
ba888a1f6d
|
|||
|
a73891fe2b
|
|||
|
6feab76abc
|
|||
|
5f46a9610e
|
|||
|
858b4bf5ad
|
|||
|
e1d71d6177
|
|||
|
5e1a7383bc
|
|||
|
3895c2f63c
|
|||
|
9d56a5ca59
|
|||
|
9978970683
|
|||
|
d2363b0801
|
|||
|
d9498659e8
|
|||
|
1242f64308
|
|||
|
5e1e2b5286
|
|||
|
da53ef8915
|
|||
|
3fea7c5612
|
|||
|
e5b6d56131
|
|||
|
0eb837dfed
|
|||
|
942b316ed0
|
|||
|
28f6791073
|
|||
|
87f5c625ff
|
|||
|
f03b7fa01c
|
|||
|
3aa7e4737e
|
|||
|
853a8c61c0
|
|||
|
951804641f
|
|||
|
5393a19225
|
|||
|
f8c1022469
|
|||
|
191066fc38
|
|||
|
f98f039fc1
|
|||
|
14882a5f01
|
|||
|
aca1dff50a
|
|||
|
f069da99c2
|
|||
|
23a8577c09
|
|||
|
5847838e16
|
|||
|
7e93d51ad2
|
|||
|
a32f930f63
|
|||
|
65664d268d
|
|||
|
2d3ecab909
|
|||
|
45a91d0472
|
|||
|
fe4045105a
|
|||
|
05179472c2
|
|||
|
2936597311
|
|||
|
3deb38725f
|
|||
|
cb473d5cff
|
|||
|
8119ce5ed9
|
|||
|
bdb9706417
|
|||
|
db1b2b9e3e
|
|||
|
21c9e33768
|
|||
|
365d27d027
|
|||
|
a80189ad08
|
|||
|
0747a0f8db
|
|||
|
6079649b00
|
|||
|
6549ac8f40
|
|||
|
9405c89574
|
|||
|
1ce2fad983
|
|||
|
9557d3c5fa
|
|||
|
f600edefc6
|
|||
|
9e3d39672e
|
|||
|
a3f70dadb1
|
|||
|
048979ae25
|
|||
|
aa7eb0bc81
|
|||
|
824d92732f
|
|||
|
fff523d732
|
|||
|
83da38fb95
|
|||
|
f0013360dc
|
|||
|
c801e01c98
|
|||
|
a6939d976e
|
|||
|
ab2435c5e6
|
|||
|
f1cb802256
|
|||
|
33bc61667b
|
|||
|
cc108b3427
|
|||
|
396b8363c1
|
|||
|
14dc316dca
|
|||
|
b0b5b8f60e
|
|||
|
1ece6e6542
|
|||
|
34af7edabf
|
|||
|
9d12749fad
|
|||
|
74552df172
|
|||
|
0611f08d96
|
|||
|
ed742a24d4
|
|||
|
a2dea1add7
|
|||
|
b112ef46d5
|
|||
|
ae6968c5b8
|
|||
|
aa0823862a
|
|||
|
323f376d5e
|
|||
|
2aa25ceb98
|
|||
|
9d594c3ea6
|
|||
|
b3ea498eb1
|
|||
|
3013cee55a
|
|||
|
5fdfba88e7
|
|||
|
49c4be0fc9
|
|||
|
55acab32ff
|
|||
|
dbf0c2ce70
|
|||
|
7d6de20e7d
|
|||
|
59363f5e4f
|
|||
|
338031d8e6
|
|||
|
7f9497312d
|
|||
|
42f4e8d86e
|
|||
|
4e95d3db80
|
|||
|
aa07d658c5
|
|||
|
b0d3b184cc
|
|||
|
b68182c838
|
|||
|
dd87cb201c
|
|||
|
bade8dd709
|
|||
|
e00e40e61e
|
|||
|
eacd35d952
|
|||
|
dd7abb9231
|
|||
|
74efeb9821
|
|||
|
f48063085b
|
|||
|
0723473037
|
|||
|
21a87d3485
|
|||
|
419bea8fe5
|
|||
|
1b72d966de
|
|||
|
97efdc4465
|
|||
|
833b43bdda
|
|||
|
d7f93c0f41
|
|||
|
e9ec7e1b08
|
|||
|
0f526fa706
|
|||
|
f343b5b82b
|
|||
|
360623b923
|
|||
|
a0019c1986
|
|||
|
7860f8ba94
|
|||
|
a895e9afc0
|
|||
|
586274f8c9
|
|||
|
337aa58346
|
|||
|
53a64c16c8
|
|||
|
c9e0541ee4
|
|||
|
9c20577a15
|
|||
|
03fc829d22
|
|||
|
5e381828b0
|
|||
|
9a63a96d83
|
|||
|
3baa493154
|
|||
|
14ef741198
|
|||
|
b820951a42
|
|||
|
4a88712709
|
|||
|
e05af14a45
|
|||
|
9661aac5ab
|
|||
|
8d6b093e14
|
|||
|
0b4d3a77a9
|
|||
|
05c493bcf9
|
|||
|
29502781d8
|
|||
|
e13c136c09
|
|||
|
8849107168
|
|||
|
39b1ed800a
|
|||
|
5a348e7c54
|
|||
|
2484fe208e
|
|||
|
2932ca1e95
|
|||
|
c471473a54
|
|||
|
ebe790f2a0
|
@@ -5,6 +5,4 @@
|
|||||||
(version 0)
|
(version 0)
|
||||||
|
|
||||||
(("6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3"
|
(("6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3"
|
||||||
(name "steffen")) ("F29B A6DA 96E5 EC29 FDDE D994 8F4F 75B3 B19D 4784"
|
(name "steffen"))))
|
||||||
(name "tribes-supertest-dev"))
|
|
||||||
))
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"mode" : "tree-sync",
|
|
||||||
"previous_dev_commit" : "593745da5e4135abc63956442e853dd2643e46ae",
|
|
||||||
"source_branch" : "origin/master",
|
|
||||||
"source_commit" : "54f23bc863ebef8173faf2aaf21801050e09fb53",
|
|
||||||
"synced_at" : "2026-06-09T07:43:46Z"
|
|
||||||
}
|
|
||||||
@@ -111,6 +111,85 @@ generation `channels` are the preferred source for the currently installed
|
|||||||
channel commit; callers can fall back to top-level `current_channels` for the
|
channel commit; callers can fall back to top-level `current_channels` for the
|
||||||
initial non-local-control install.
|
initial non-local-control install.
|
||||||
|
|
||||||
|
### `POST /v1/certificates/edge/install`
|
||||||
|
|
||||||
|
Synchronous. Installs a Tribes-issued public edge certificate for HAProxy and
|
||||||
|
reloads HAProxy. This endpoint is intended for the Tribes ACME renewal worker;
|
||||||
|
it does not store desired certificate configuration.
|
||||||
|
|
||||||
|
Body:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"fullchain_path": "/var/lib/tribes/acme/edge.fullchain.pem",
|
||||||
|
"private_key_path": "/var/lib/tribes/acme/edge.key"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
- Both paths must be under `/var/lib/tribes/acme/`.
|
||||||
|
- Both files must already exist.
|
||||||
|
- local-control writes `/var/lib/tribes/acme/edge.full.pem` as fullchain plus
|
||||||
|
private key for HAProxy.
|
||||||
|
- local-control reloads `haproxy` after the file swap.
|
||||||
|
|
||||||
|
Successful response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"ok": true}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `POST /v1/edge/identity/update`
|
||||||
|
|
||||||
|
Synchronous. Atomically updates the node-local edge identity fields in
|
||||||
|
`/etc/tribes/host-config.json`. This endpoint is intended for Tribes after an
|
||||||
|
admin API caller, such as Legion, has changed DNS/certificate desired state.
|
||||||
|
It does not run Guix or issue certificates itself.
|
||||||
|
|
||||||
|
Body:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"public_host": "supertest.tribe-one.org",
|
||||||
|
"apex_host": "supertest.tribe-one.org",
|
||||||
|
"node_host": "node1.supertest.tribe-one.org",
|
||||||
|
"public_ipv4": "178.156.143.247",
|
||||||
|
"public_ipv6": "2a01:4ff:f0:63ba::73be",
|
||||||
|
"certificate_subjects": [
|
||||||
|
"178.156.143.247",
|
||||||
|
"2a01:4ff:f0:63ba::73be",
|
||||||
|
"node1.supertest.tribe-one.org",
|
||||||
|
"supertest.tribe-one.org"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`public_host` is optional when candidates are present; local-control chooses
|
||||||
|
`public_host`, then apex, then node host, then IPv4, then IPv6. The endpoint
|
||||||
|
updates:
|
||||||
|
|
||||||
|
- `tribes.host`
|
||||||
|
- `tribes.sync_host` when it previously tracked the old `tribes.host`
|
||||||
|
- `edge.certificate_subjects`
|
||||||
|
|
||||||
|
If `tribes.host` changes, local-control schedules an asynchronous `herd restart
|
||||||
|
tribes` after the response has been sent. Tribes then reloads runtime config
|
||||||
|
from `host-config.json`; certificate reconciliation is owned by Tribes.
|
||||||
|
|
||||||
|
Successful response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"public_host": "supertest.tribe-one.org",
|
||||||
|
"certificate_subjects": ["..."],
|
||||||
|
"public_host_changed": true,
|
||||||
|
"certificate_subjects_changed": true,
|
||||||
|
"tribes_restart_scheduled": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `POST /v1/channels/updates`
|
### `POST /v1/channels/updates`
|
||||||
|
|
||||||
Synchronous. Discovers update candidates for configured channels by using the
|
Synchronous. Discovers update candidates for configured channels by using the
|
||||||
|
|||||||
@@ -1,48 +1,47 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": "1",
|
"schema_version": "1",
|
||||||
"tribes": {
|
"tribes": {
|
||||||
"workingDirectory": "/var/lib/tribes",
|
"working_directory": "/var/lib/tribes",
|
||||||
"serviceUser": "tribes",
|
"service_user": "tribes",
|
||||||
"serviceGroup": "tribes",
|
"service_group": "tribes",
|
||||||
"host": "node1.example.invalid",
|
"host": "203.0.113.10",
|
||||||
"listenAddress": "127.0.0.1",
|
"listen_address": "127.0.0.1",
|
||||||
"listenPort": 4000,
|
"listen_port": 4000,
|
||||||
"scheme": "https",
|
"scheme": "https",
|
||||||
"port": 443,
|
"port": 443,
|
||||||
"syncHost": "node1.example.invalid",
|
"sync_host": "203.0.113.10",
|
||||||
"syncPort": 4413,
|
"sync_port": 4413,
|
||||||
"syncBindAddress": "0.0.0.0",
|
"sync_bind_address": "0.0.0.0",
|
||||||
"syncUrl": "wss://node1.example.invalid:4413/relay",
|
"sync_url": "wss://203.0.113.10:4413/relay",
|
||||||
"syncTlsCertFile": "/var/lib/tribes/secrets/sync/node.pem",
|
"sync_tls_cert_file": "/var/lib/tribes/secrets/sync/node.pem",
|
||||||
"syncTlsKeyFile": "/var/lib/tribes/secrets/sync/node-key.pem",
|
"sync_tls_key_file": "/var/lib/tribes/secrets/sync/node-key.pem",
|
||||||
"syncTlsCaCertFile": "/var/lib/tribes/secrets/sync/ca.pem",
|
"sync_tls_ca_cert_file": "/var/lib/tribes/secrets/sync/ca.pem",
|
||||||
"adminPubkeys": [],
|
"admin_pubkeys": [],
|
||||||
"databaseUser": "tribes",
|
"database_user": "tribes",
|
||||||
"databaseName": "tribes",
|
"database_name": "tribes",
|
||||||
"parrhesiaDatabaseName": "parrhesia",
|
"parrhesia_database_name": "parrhesia",
|
||||||
"databaseHost": "/var/run/postgresql",
|
"database_host": "/var/run/postgresql",
|
||||||
"secretKeyBaseFile": "/var/lib/tribes/secrets/secret_key_base",
|
"secret_key_base_file": "/var/lib/tribes/secrets/secret_key_base",
|
||||||
"tokenSigningSecretFile": "/var/lib/tribes/secrets/token_signing_secret",
|
"token_signing_secret_file": "/var/lib/tribes/secrets/token_signing_secret",
|
||||||
"releaseCookieFile": "/var/lib/tribes/secrets/release_cookie",
|
"release_cookie_file": "/var/lib/tribes/secrets/release_cookie",
|
||||||
"releaseDistribution": "name",
|
"release_distribution": "name",
|
||||||
"releaseNode": "tribes@127.0.0.1",
|
"release_node": "tribes@127.0.0.1",
|
||||||
"extraEnvironmentVariables": [
|
"extra_environment_variables": [
|
||||||
"TRIBES_BOOTSTRAP_FILE=/etc/tribes/bootstrap.json"
|
"TRIBES_BOOTSTRAP_FILE=/etc/tribes/bootstrap.json"
|
||||||
],
|
],
|
||||||
"logFile": "/var/log/tribes/tribes.log"
|
"log_file": "/var/log/tribes/tribes.log"
|
||||||
},
|
},
|
||||||
"edge": {
|
"edge": {
|
||||||
"certificateName": "node1-example-invalid",
|
"certificate_name": "203-0-113-10",
|
||||||
"certificateSubjects": ["node1.example.invalid"],
|
"certificate_subjects": ["203.0.113.10"],
|
||||||
"certificateEmail": "ops@example.invalid",
|
"certificate_profile": "shortlived",
|
||||||
"certificateProfile": "shortlived",
|
"renew_days": 4,
|
||||||
"renewDays": 4,
|
"http_port": 80,
|
||||||
"httpPort": 80,
|
"https_port": 443,
|
||||||
"httpsPort": 443,
|
"challenge_address": "127.0.0.1",
|
||||||
"challengeAddress": "127.0.0.1",
|
"challenge_port": 8080,
|
||||||
"challengePort": 8080,
|
"cache_address": "127.0.0.1",
|
||||||
"cacheAddress": "127.0.0.1",
|
"cache_port": 6081,
|
||||||
"cachePort": 6081,
|
"cache_storage": ["malloc,256M"]
|
||||||
"cacheStorage": ["malloc,256M"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
;;; Manifest of upstream source origins for every package defined by the
|
||||||
|
;;; tribes channel. Consumed by Cuirass's `manifests' build type as a
|
||||||
|
;;; network-bound canary: fast-fails when an upstream URL or commit ref
|
||||||
|
;;; becomes unreachable, without depending on any actual package build.
|
||||||
|
|
||||||
|
(define-module (manifests sources)
|
||||||
|
#:use-module (gnu packages)
|
||||||
|
#:use-module (guix discovery)
|
||||||
|
#:use-module (guix packages)
|
||||||
|
#:use-module (guix profiles)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
|
#:use-module (ice-9 vlist)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-26)
|
||||||
|
#:export (sources-manifest))
|
||||||
|
|
||||||
|
(define (channel-module-path prefix)
|
||||||
|
(delete-duplicates
|
||||||
|
(filter-map (lambda (dir)
|
||||||
|
(let ((path (string-append dir "/" prefix)))
|
||||||
|
(and (file-exists? path) (cons dir prefix))))
|
||||||
|
%load-path)
|
||||||
|
equal?))
|
||||||
|
|
||||||
|
(define (channel-packages)
|
||||||
|
(fold-packages cons '()
|
||||||
|
(append (all-modules (channel-module-path "tribes/packages"))
|
||||||
|
(all-modules (channel-module-path "nbde/packages")))))
|
||||||
|
|
||||||
|
(define (upstream-origin source)
|
||||||
|
(origin (inherit source) (snippet #f) (patches '())))
|
||||||
|
|
||||||
|
(define (channel-origins)
|
||||||
|
(let loop ((packages (channel-packages))
|
||||||
|
(origins '())
|
||||||
|
(visited vlist-null))
|
||||||
|
(match packages
|
||||||
|
((head . tail)
|
||||||
|
(let ((new (remove (cut vhash-assq <> visited)
|
||||||
|
(package-direct-sources head))))
|
||||||
|
(loop tail (append new origins)
|
||||||
|
(fold (cut vhash-consq <> #t <>)
|
||||||
|
visited new))))
|
||||||
|
(() origins))))
|
||||||
|
|
||||||
|
(define sources-manifest
|
||||||
|
(manifest (map (lambda (origin)
|
||||||
|
(manifest-entry
|
||||||
|
(name (or (origin-actual-file-name origin) "origin"))
|
||||||
|
(version "0")
|
||||||
|
(item (upstream-origin origin))))
|
||||||
|
(channel-origins))))
|
||||||
|
|
||||||
|
sources-manifest
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
(define-module (manifests substitutes base)
|
|
||||||
#:use-module (gnu packages)
|
|
||||||
#:use-module (gnu packages elixir)
|
|
||||||
#:use-module (gnu packages erlang)
|
|
||||||
#:use-module (guix profiles)
|
|
||||||
#:use-module (nbde packages crypto)
|
|
||||||
#:use-module (tribes packages terminals)
|
|
||||||
#:export (base-manifest))
|
|
||||||
|
|
||||||
(define %base-specifications
|
|
||||||
'("bash-minimal"
|
|
||||||
"coreutils"
|
|
||||||
"diffutils"
|
|
||||||
"findutils"
|
|
||||||
"gawk"
|
|
||||||
"grep"
|
|
||||||
"gzip"
|
|
||||||
"inetutils"
|
|
||||||
"iproute2"
|
|
||||||
"less"
|
|
||||||
"nss-certs"
|
|
||||||
"openssh"
|
|
||||||
"postgresql"
|
|
||||||
"procps"
|
|
||||||
"rsync"
|
|
||||||
"sed"
|
|
||||||
"tar"
|
|
||||||
"which"
|
|
||||||
"xz"
|
|
||||||
"cryptsetup"
|
|
||||||
"dosfstools"
|
|
||||||
"e2fsprogs"
|
|
||||||
"gptfdisk"
|
|
||||||
"kmod"
|
|
||||||
"parted"
|
|
||||||
"util-linux"))
|
|
||||||
|
|
||||||
(define base-manifest
|
|
||||||
(packages->manifest
|
|
||||||
(append (map specification->package %base-specifications)
|
|
||||||
(list clevis
|
|
||||||
tang
|
|
||||||
luksmeta
|
|
||||||
erlang
|
|
||||||
elixir
|
|
||||||
elixir-hex
|
|
||||||
ghostty-terminfo))))
|
|
||||||
|
|
||||||
base-manifest
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
(define-module (manifests substitutes installer)
|
|
||||||
#:use-module (gnu packages)
|
|
||||||
#:use-module (guix profiles)
|
|
||||||
#:use-module (nbde packages crypto)
|
|
||||||
#:export (installer-manifest))
|
|
||||||
|
|
||||||
(define %installer-specifications
|
|
||||||
'("bash-minimal"
|
|
||||||
"coreutils"
|
|
||||||
"diffutils"
|
|
||||||
"findutils"
|
|
||||||
"gawk"
|
|
||||||
"git-minimal"
|
|
||||||
"grep"
|
|
||||||
"gzip"
|
|
||||||
"guix"
|
|
||||||
"inetutils"
|
|
||||||
"iproute2"
|
|
||||||
"kexec-tools"
|
|
||||||
"less"
|
|
||||||
"curl"
|
|
||||||
"nss-certs"
|
|
||||||
"procps"
|
|
||||||
"rsync"
|
|
||||||
"sed"
|
|
||||||
"tar"
|
|
||||||
"which"
|
|
||||||
"zstd"
|
|
||||||
"xz"
|
|
||||||
"console-setup"
|
|
||||||
"cryptsetup"
|
|
||||||
"dosfstools"
|
|
||||||
"grub-efi"
|
|
||||||
"grub-pc"
|
|
||||||
"mdadm"
|
|
||||||
"e2fsprogs"
|
|
||||||
"gptfdisk"
|
|
||||||
"kmod"
|
|
||||||
"parted"
|
|
||||||
"util-linux"))
|
|
||||||
|
|
||||||
(define installer-manifest
|
|
||||||
(packages->manifest
|
|
||||||
(append (map specification->package %installer-specifications)
|
|
||||||
(list clevis
|
|
||||||
luksmeta))))
|
|
||||||
|
|
||||||
installer-manifest
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
(define-module (manifests substitutes tribes-node)
|
|
||||||
#:use-module (gnu packages)
|
|
||||||
#:use-module (gnu packages elixir)
|
|
||||||
#:use-module (gnu packages erlang)
|
|
||||||
#:use-module (gnu packages monitoring)
|
|
||||||
#:use-module (guix profiles)
|
|
||||||
#:use-module (tribes packages monitoring)
|
|
||||||
#:use-module (tribes packages source)
|
|
||||||
#:use-module (tribes packages terminals)
|
|
||||||
#:use-module (tribes packages web)
|
|
||||||
#:use-module (tribes plugins registry)
|
|
||||||
#:export (tribes-node-manifest
|
|
||||||
make-tribes-node-manifest))
|
|
||||||
|
|
||||||
(define %tribes-node-specifications
|
|
||||||
'("nss-certs"
|
|
||||||
"openssh"
|
|
||||||
"postgresql"
|
|
||||||
"rsync"
|
|
||||||
"ripgrep"
|
|
||||||
"fd"
|
|
||||||
"tmux"
|
|
||||||
"neovim"
|
|
||||||
"btop"))
|
|
||||||
|
|
||||||
(define (getenv/default name default)
|
|
||||||
(or (getenv name) default))
|
|
||||||
|
|
||||||
(define (tribes-node-package)
|
|
||||||
(let ((source-directory (getenv "TRIBES_SOURCE_DIRECTORY")))
|
|
||||||
(if source-directory
|
|
||||||
(local-tribes-package
|
|
||||||
source-directory
|
|
||||||
#:version (getenv/default "TRIBES_RELEASE_VERSION" "dev")
|
|
||||||
#:mix-deps-sha256 (getenv "TRIBES_MIX_DEPS_SHA256")
|
|
||||||
#:raw-mix-deps-sha256 (getenv "TRIBES_RAW_MIX_DEPS_SHA256")
|
|
||||||
#:npm-deps-sha256 (getenv "TRIBES_NPM_DEPS_SHA256"))
|
|
||||||
tribes-package)))
|
|
||||||
|
|
||||||
(define (make-tribes-node-manifest)
|
|
||||||
(packages->manifest
|
|
||||||
(append
|
|
||||||
(map specification->package %tribes-node-specifications)
|
|
||||||
(list erlang
|
|
||||||
elixir
|
|
||||||
elixir-hex
|
|
||||||
ghostty-terminfo
|
|
||||||
haproxy
|
|
||||||
vinyl
|
|
||||||
lego
|
|
||||||
prometheus-node-exporter
|
|
||||||
victoriametrics
|
|
||||||
vinyl-exporter
|
|
||||||
(tribes-node-package))
|
|
||||||
(guix-tribes-plugin-substitute-packages))))
|
|
||||||
|
|
||||||
(define tribes-node-manifest
|
|
||||||
(make-tribes-node-manifest))
|
|
||||||
|
|
||||||
tribes-node-manifest
|
|
||||||
@@ -55,7 +55,10 @@
|
|||||||
util-linux)))
|
util-linux)))
|
||||||
|
|
||||||
(define %build-host-kexec-initrd-modules
|
(define %build-host-kexec-initrd-modules
|
||||||
'("ahci"
|
'(;; Common block/storage basics.
|
||||||
|
"ahci"
|
||||||
|
"ata_piix"
|
||||||
|
"cdrom"
|
||||||
"dm-crypt"
|
"dm-crypt"
|
||||||
"fat"
|
"fat"
|
||||||
"loop"
|
"loop"
|
||||||
@@ -64,13 +67,19 @@
|
|||||||
"nvme"
|
"nvme"
|
||||||
"overlay"
|
"overlay"
|
||||||
"sd_mod"
|
"sd_mod"
|
||||||
|
"sr_mod"
|
||||||
"squashfs"
|
"squashfs"
|
||||||
"vfat"
|
"vfat"
|
||||||
|
|
||||||
|
;; KVM/QEMU and common emulated or non-virtio NICs.
|
||||||
"virtio_blk"
|
"virtio_blk"
|
||||||
"virtio_console"
|
"virtio_console"
|
||||||
"virtio_net"
|
"virtio_net"
|
||||||
"virtio_pci"
|
"virtio_pci"
|
||||||
"virtio_scsi"))
|
"virtio_scsi"
|
||||||
|
"e1000"
|
||||||
|
"e1000e"
|
||||||
|
"r8169"))
|
||||||
|
|
||||||
(define build-host-kexec-installer-os
|
(define build-host-kexec-installer-os
|
||||||
(operating-system
|
(operating-system
|
||||||
@@ -84,9 +93,10 @@
|
|||||||
(initrd kexec-installer-initrd)
|
(initrd kexec-installer-initrd)
|
||||||
(kernel-arguments
|
(kernel-arguments
|
||||||
'("console=ttyS0,115200n8"
|
'("console=ttyS0,115200n8"
|
||||||
|
"console=tty0"
|
||||||
"net.ifnames=0"
|
"net.ifnames=0"
|
||||||
"panic=30"
|
"panic=30"
|
||||||
"loglevel=4"))
|
"loglevel=6"))
|
||||||
(bootloader
|
(bootloader
|
||||||
(bootloader-configuration
|
(bootloader-configuration
|
||||||
(bootloader grub-bootloader)
|
(bootloader grub-bootloader)
|
||||||
|
|||||||
@@ -28,8 +28,9 @@
|
|||||||
(locale "en_US.UTF-8")
|
(locale "en_US.UTF-8")
|
||||||
(kernel tribes-linux)
|
(kernel tribes-linux)
|
||||||
(kernel-arguments
|
(kernel-arguments
|
||||||
(list "console=tty0"
|
(list "console=ttyS0,115200n8"
|
||||||
"console=ttyS0,115200n8"))
|
"console=tty0"
|
||||||
|
"net.ifnames=0"))
|
||||||
(initrd
|
(initrd
|
||||||
(lambda (file-systems . rest)
|
(lambda (file-systems . rest)
|
||||||
(apply base-initrd
|
(apply base-initrd
|
||||||
|
|||||||
@@ -48,8 +48,9 @@
|
|||||||
(locale "en_US.UTF-8")
|
(locale "en_US.UTF-8")
|
||||||
(kernel tribes-linux)
|
(kernel tribes-linux)
|
||||||
(kernel-arguments
|
(kernel-arguments
|
||||||
(list "console=tty0"
|
(list "console=ttyS0,115200n8"
|
||||||
"console=ttyS0,115200n8"))
|
"console=tty0"
|
||||||
|
"net.ifnames=0"))
|
||||||
(initrd-modules
|
(initrd-modules
|
||||||
(append %nbde-initrd-modules
|
(append %nbde-initrd-modules
|
||||||
%base-initrd-modules))
|
%base-initrd-modules))
|
||||||
@@ -72,7 +73,9 @@ runtime-discovered boot and filesystem values from the installer."
|
|||||||
(append
|
(append
|
||||||
extra-services
|
extra-services
|
||||||
(list (boot-store-staging-service)
|
(list (boot-store-staging-service)
|
||||||
(service dhcpcd-service-type)
|
(service dhcpcd-service-type
|
||||||
|
(dhcpcd-configuration
|
||||||
|
(interfaces (list interface))))
|
||||||
(service elogind-service-type)
|
(service elogind-service-type)
|
||||||
(service agetty-service-type
|
(service agetty-service-type
|
||||||
(agetty-configuration
|
(agetty-configuration
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
(list (channel
|
(list (channel
|
||||||
(name 'guix)
|
(name 'guix)
|
||||||
(url "https://git.teralink.net/tribes/guix-fork.git")
|
(url "https://git.teralink.net/tribes/guix-fork.git")
|
||||||
(branch "refactor/substituter-trace-framing")
|
(branch "feature/substitute-read-timeout")
|
||||||
;; guix-fork refactor/substituter-trace-framing
|
;; guix-fork feature/substitute-read-timeout
|
||||||
(commit
|
(commit
|
||||||
"8514f9c1a98468c044e8b5f65e4a90d097a63a47")
|
"4574af27f27c7a5d2dc4d4823ef4518a392dc973")
|
||||||
(introduction
|
(introduction
|
||||||
(make-channel-introduction
|
(make-channel-introduction
|
||||||
"093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
"093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
(channel
|
(channel
|
||||||
(name 'guix)
|
(name 'guix)
|
||||||
(url "https://git.teralink.net/tribes/guix-fork.git")
|
(url "https://git.teralink.net/tribes/guix-fork.git")
|
||||||
(branch "refactor/substituter-trace-framing")
|
(branch "feature/substitute-read-timeout")
|
||||||
;; guix-fork refactor/substituter-trace-framing
|
;; guix-fork feature/substitute-read-timeout
|
||||||
(commit
|
(commit
|
||||||
"8514f9c1a98468c044e8b5f65e4a90d097a63a47")
|
"4574af27f27c7a5d2dc4d4823ef4518a392dc973")
|
||||||
(introduction
|
(introduction
|
||||||
(make-channel-introduction
|
(make-channel-introduction
|
||||||
"093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
"093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ load_guix_env
|
|||||||
require_tool guix
|
require_tool guix
|
||||||
require_tool guile
|
require_tool guile
|
||||||
require_tool mksquashfs
|
require_tool mksquashfs
|
||||||
|
require_tool cpio
|
||||||
require_file "$channels" "channels file"
|
require_file "$channels" "channels file"
|
||||||
require_file "$script_dir/kexec-run" "kexec runner"
|
require_file "$script_dir/kexec-run" "kexec runner"
|
||||||
require_file "$root_dir/examples/build-host-kexec-installer.scm" "system file"
|
require_file "$root_dir/examples/build-host-kexec-installer.scm" "system file"
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ base_output="${NBDE_BASE_CHANNELS_OUTPUT:-$root_dir/pins/base-channels.sexp}"
|
|||||||
legion_output="${NBDE_LEGION_CHANNELS_OUTPUT:-$root_dir/pins/legion-channels.sexp}"
|
legion_output="${NBDE_LEGION_CHANNELS_OUTPUT:-$root_dir/pins/legion-channels.sexp}"
|
||||||
|
|
||||||
fork_url="https://git.teralink.net/tribes/guix-fork.git"
|
fork_url="https://git.teralink.net/tribes/guix-fork.git"
|
||||||
fork_branch="refactor/substituter-trace-framing"
|
fork_branch="feature/substitute-read-timeout"
|
||||||
fork_introduction_commit="093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
fork_introduction_commit="093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
||||||
fork_introduction_signer="6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3"
|
fork_introduction_signer="6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3"
|
||||||
fork_checkout="$root_dir/../guix-fork"
|
fork_checkout="$root_dir/../guix-fork"
|
||||||
fork_comment="guix-fork refactor/substituter-trace-framing"
|
fork_comment="guix-fork feature/substitute-read-timeout"
|
||||||
|
|
||||||
official_url="https://git.teralink.net/tribes/guix.git"
|
official_url="https://git.teralink.net/tribes/guix.git"
|
||||||
official_branch="master"
|
official_branch="master"
|
||||||
|
|||||||
+46
-10
@@ -16,13 +16,19 @@ Usage: update-plugin-pin [options] plugin [rev]
|
|||||||
|
|
||||||
Pin a Tribes external plugin and refresh fixed-output hashes.
|
Pin a Tribes external plugin and refresh fixed-output hashes.
|
||||||
|
|
||||||
PLUGIN is the plugin slug. REV defaults to "master" resolved from the
|
PLUGIN is the canonical plugin slug or, for older plugin layouts, the source
|
||||||
plugin checkout. The plugin manifest.json is the source of truth for plugin
|
repository basename. REV defaults to "master" resolved from the plugin checkout.
|
||||||
id, slug, version, provides, and requires metadata. By default the script expects
|
The plugin manifest.json is the source of truth for plugin id, slug, version,
|
||||||
the plugin checkout at ../tribes-plugin-$PLUGIN and the Guix plugin file at
|
provides, and requires metadata. By default the script expects the plugin
|
||||||
tribes/plugins/$PLUGIN.scm relative to the guix-tribes checkout.
|
checkout at ../tribes-plugin-$PLUGIN and the Guix plugin file at
|
||||||
|
tribes/plugins/$PLUGIN.scm relative to the guix-tribes checkout. If those do not
|
||||||
|
exist and PLUGIN starts with tribe-one-, it also tries the unprefixed source
|
||||||
|
basename. Use --plugin-source-name when the source repository and Guix file
|
||||||
|
basename differ from the canonical slug.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
--plugin-source-name NAME
|
||||||
|
Source repository, Guix file, package, and Scheme symbol basename
|
||||||
--plugin-repo PATH Local plugin git checkout
|
--plugin-repo PATH Local plugin git checkout
|
||||||
--plugin-file PATH Guix plugin definition file to update
|
--plugin-file PATH Guix plugin definition file to update
|
||||||
--tribes-repo PATH Local Tribes git checkout used for the host plugin API
|
--tribes-repo PATH Local Tribes git checkout used for the host plugin API
|
||||||
@@ -133,6 +139,7 @@ my %opts;
|
|||||||
|
|
||||||
GetOptionsFromArray(
|
GetOptionsFromArray(
|
||||||
\@argv,
|
\@argv,
|
||||||
|
'plugin-source-name=s' => \$opts{plugin_source_name},
|
||||||
'plugin-repo=s' => \$opts{plugin_repo},
|
'plugin-repo=s' => \$opts{plugin_repo},
|
||||||
'plugin-file=s' => \$opts{plugin_file},
|
'plugin-file=s' => \$opts{plugin_file},
|
||||||
'tribes-repo=s' => \$opts{tribes_repo},
|
'tribes-repo=s' => \$opts{tribes_repo},
|
||||||
@@ -168,16 +175,37 @@ my $default_tribes_repo = abs_path(File::Spec->catdir($default_guix_repo, '..',
|
|||||||
|
|
||||||
my $guix_repo = $opts{guix_repo} ? abs_path($opts{guix_repo}) : $default_guix_repo;
|
my $guix_repo = $opts{guix_repo} ? abs_path($opts{guix_repo}) : $default_guix_repo;
|
||||||
my $tribes_repo = $opts{tribes_repo} ? abs_path($opts{tribes_repo}) : $default_tribes_repo;
|
my $tribes_repo = $opts{tribes_repo} ? abs_path($opts{tribes_repo}) : $default_tribes_repo;
|
||||||
|
|
||||||
|
sub default_plugin_source_name {
|
||||||
|
my ($plugin, $guix_repo) = @_;
|
||||||
|
my @candidates = ($plugin);
|
||||||
|
|
||||||
|
if ($plugin =~ /^tribe-one-(.+)$/) {
|
||||||
|
push @candidates, $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $candidate (@candidates) {
|
||||||
|
my $repo = File::Spec->catdir($guix_repo, '..', "tribes-plugin-$candidate");
|
||||||
|
my $file = File::Spec->catfile($guix_repo, 'tribes', 'plugins', "$candidate.scm");
|
||||||
|
return $candidate if -d File::Spec->catdir($repo, '.git') && -f $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $plugin_source_name = $opts{plugin_source_name} // default_plugin_source_name($plugin, $guix_repo);
|
||||||
|
$plugin_source_name =~ /^[A-Za-z0-9._+-]+$/ or fail("Invalid plugin source name: $plugin_source_name");
|
||||||
|
|
||||||
my $plugin_repo =
|
my $plugin_repo =
|
||||||
$opts{plugin_repo}
|
$opts{plugin_repo}
|
||||||
? abs_path($opts{plugin_repo})
|
? abs_path($opts{plugin_repo})
|
||||||
: abs_path(File::Spec->catdir($guix_repo, '..', "tribes-plugin-$plugin"));
|
: abs_path(File::Spec->catdir($guix_repo, '..', "tribes-plugin-$plugin_source_name"));
|
||||||
my $plugin_file =
|
my $plugin_file =
|
||||||
$opts{plugin_file}
|
$opts{plugin_file}
|
||||||
? abs_path($opts{plugin_file})
|
? abs_path($opts{plugin_file})
|
||||||
: File::Spec->catfile($guix_repo, 'tribes', 'plugins', "$plugin.scm");
|
: File::Spec->catfile($guix_repo, 'tribes', 'plugins', "$plugin_source_name.scm");
|
||||||
my $source_file = File::Spec->catfile($guix_repo, 'tribes', 'packages', 'source.scm');
|
my $source_file = File::Spec->catfile($guix_repo, 'tribes', 'packages', 'source.scm');
|
||||||
my $plugin_package_name = "tribes-plugin-$plugin";
|
my $plugin_package_name = "tribes-plugin-$plugin_source_name";
|
||||||
|
|
||||||
-d File::Spec->catdir($plugin_repo, '.git') or fail("Plugin repo not found: $plugin_repo");
|
-d File::Spec->catdir($plugin_repo, '.git') or fail("Plugin repo not found: $plugin_repo");
|
||||||
-d File::Spec->catdir($tribes_repo, '.git') or fail("Tribes repo not found: $tribes_repo");
|
-d File::Spec->catdir($tribes_repo, '.git') or fail("Tribes repo not found: $tribes_repo");
|
||||||
@@ -253,7 +281,14 @@ my $version = $manifest->{version};
|
|||||||
my $provides_joined = join("\037", @{ $manifest->{provides} });
|
my $provides_joined = join("\037", @{ $manifest->{provides} });
|
||||||
my $requires_joined = join("\037", @{ $manifest->{requires} });
|
my $requires_joined = join("\037", @{ $manifest->{requires} });
|
||||||
|
|
||||||
$plugin_slug eq $plugin or fail("Plugin manifest slug mismatch: expected $plugin, got $plugin_slug");
|
if ($plugin_slug ne $plugin) {
|
||||||
|
if (!defined($opts{plugin_source_name}) && $plugin eq $plugin_source_name) {
|
||||||
|
print STDERR "Plugin argument '$plugin' matched source name; using manifest slug '$plugin_slug'.\n";
|
||||||
|
$plugin = $plugin_slug;
|
||||||
|
} else {
|
||||||
|
fail("Plugin manifest slug mismatch: expected $plugin, got $plugin_slug");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
my ($plugin_source_for_scheme, $tribes_source_for_scheme, $guix_load_path);
|
my ($plugin_source_for_scheme, $tribes_source_for_scheme, $guix_load_path);
|
||||||
my $source_hash;
|
my $source_hash;
|
||||||
@@ -348,7 +383,7 @@ my $dummy_hash = '0' x 52;
|
|||||||
|
|
||||||
my $text = read_file($plugin_file);
|
my $text = read_file($plugin_file);
|
||||||
my @candidates;
|
my @candidates;
|
||||||
for my $candidate ($plugin, ($plugin =~ tr/_/-/r)) {
|
for my $candidate ($plugin_source_name, ($plugin_source_name =~ tr/_/-/r)) {
|
||||||
push @candidates, $candidate unless grep { $_ eq $candidate } @candidates;
|
push @candidates, $candidate unless grep { $_ eq $candidate } @candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,6 +537,7 @@ write_file($plugin_file, $text);
|
|||||||
|
|
||||||
print "Updated $plugin_file\n";
|
print "Updated $plugin_file\n";
|
||||||
print "plugin: $plugin\n";
|
print "plugin: $plugin\n";
|
||||||
|
print "plugin source name: $plugin_source_name\n" if $plugin_source_name ne $plugin;
|
||||||
print "plugin id: $plugin_id\n";
|
print "plugin id: $plugin_id\n";
|
||||||
print "commit: $commit\n";
|
print "commit: $commit\n";
|
||||||
print "host tribes commit: $host_commit\n";
|
print "host tribes commit: $host_commit\n";
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
# External plugin pins to refresh. Each name maps to ../tribes-plugin-$name
|
# External plugin pins to refresh. Each entry is canonical-slug:source-name.
|
||||||
# and tribes/plugins/$name.scm unless update-plugin-pin is called with
|
# The source name maps to ../tribes-plugin-$source_name and
|
||||||
# different defaults in the future.
|
# tribes/plugins/$source_name.scm.
|
||||||
plugins="sender aether supertest kobold trust"
|
plugins="tribe-one-sender:sender tribe-one-aether:aether tribe-one-supertest:supertest tribe-one-kobold:kobold tribe-one-trust:trust"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
@@ -86,11 +86,15 @@ fi
|
|||||||
--tribes-repo "$tribes_repo" \
|
--tribes-repo "$tribes_repo" \
|
||||||
$build_host_args
|
$build_host_args
|
||||||
|
|
||||||
for plugin in $plugins; do
|
for plugin_entry in $plugins; do
|
||||||
|
plugin=${plugin_entry%%:*}
|
||||||
|
plugin_source_name=${plugin_entry#*:}
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
"$update_plugin_pin" \
|
"$update_plugin_pin" \
|
||||||
--guix-repo "$guix_repo" \
|
--guix-repo "$guix_repo" \
|
||||||
--tribes-repo "$tribes_repo" \
|
--tribes-repo "$tribes_repo" \
|
||||||
|
--plugin-source-name "$plugin_source_name" \
|
||||||
$build_host_args \
|
$build_host_args \
|
||||||
"$plugin"
|
"$plugin"
|
||||||
done
|
done
|
||||||
@@ -99,8 +103,9 @@ if [ "$commit_after" = true ]; then
|
|||||||
git -C "$guix_repo" add -- \
|
git -C "$guix_repo" add -- \
|
||||||
tribes/packages/source.scm
|
tribes/packages/source.scm
|
||||||
|
|
||||||
for plugin in $plugins; do
|
for plugin_entry in $plugins; do
|
||||||
git -C "$guix_repo" add -- "tribes/plugins/$plugin.scm"
|
plugin_source_name=${plugin_entry#*:}
|
||||||
|
git -C "$guix_repo" add -- "tribes/plugins/$plugin_source_name.scm"
|
||||||
done
|
done
|
||||||
|
|
||||||
if git -C "$guix_repo" diff --cached --quiet; then
|
if git -C "$guix_repo" diff --cached --quiet; then
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
|
|
||||||
mDMEafMY7xYJKwYBBAHaRw8BAQdAX7Cs0UPcvEpHOwmTDkjNBfeH6/FH6sqKZbRi
|
|
||||||
sd3oBCy0U1RyaWJlcyBTdXBlcnRlc3QgRGV2IChBSSBsb2NhbCBkZXZlbG9wbWVu
|
|
||||||
dCBrZXkpIDx0cmliZXMtc3VwZXJ0ZXN0LWRldkB0ZXJhbGluay5uZXQ+iJYEExYK
|
|
||||||
AD4WIQTym6baluXsKf3e2ZSPT3WzsZ1HhAUCafMY7wIbAwUJAeEzgAULCQgHAgYV
|
|
||||||
CgkICwIEFgIDAQIeAQIXgAAKCRCPT3WzsZ1HhMp8AP4gGrPkBoGLKMyubISESFpH
|
|
||||||
fnqYUGDGucIoLRvtbl+ULQD/SlC9u/Ek9WSYvsskd0jD09lc2TxBnubl8yRi3bTM
|
|
||||||
sA8=
|
|
||||||
=JA7U
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
(operating-system-host-name kobold-edge-operating-system))
|
(operating-system-host-name kobold-edge-operating-system))
|
||||||
|
|
||||||
(test-equal "kobold target includes trust provider"
|
(test-equal "kobold target includes trust provider"
|
||||||
'("trust" "kobold")
|
'("tribe-one-trust" "tribe-one-kobold")
|
||||||
(target-plugin-names kobold-edge-operating-system))
|
(target-plugin-names kobold-edge-operating-system))
|
||||||
|
|
||||||
(test-equal "sender target has expected host name"
|
(test-equal "sender target has expected host name"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
(define-module (tests tribes-deploy-executor)
|
(define-module (tests tribes-deploy-executor)
|
||||||
#:use-module (srfi srfi-64)
|
#:use-module (srfi srfi-64)
|
||||||
|
#:use-module (tests support)
|
||||||
#:use-module (tribes deploy executor)
|
#:use-module (tribes deploy executor)
|
||||||
#:use-module (tribes deploy plan)
|
#:use-module (tribes deploy plan)
|
||||||
#:use-module (tribes packages plugins)
|
#:use-module (tribes packages plugins)
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
(define valid-target
|
(define valid-target
|
||||||
`(("trusted_signers" . (,valid-signer))
|
`(("trusted_signers" . (,valid-signer))
|
||||||
("channels" . (,valid-channel))
|
("channels" . (,valid-channel))
|
||||||
("plugins" . ((("plugin_name" . "aether")
|
("plugins" . ((("plugin_name" . "tribe-one-aether")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
("enabled" . #t))))))
|
("enabled" . #t))))))
|
||||||
|
|
||||||
@@ -39,33 +40,33 @@
|
|||||||
(test-equal "deployment request plugins default to empty list"
|
(test-equal "deployment request plugins default to empty list"
|
||||||
'()
|
'()
|
||||||
(deployment-request-plugins
|
(deployment-request-plugins
|
||||||
'(("schemaVersion" . "1")
|
'(("schema_version" . "1")
|
||||||
("action" . "apply"))))
|
("action" . "apply"))))
|
||||||
|
|
||||||
(test-equal "deployment request plugins preserve names"
|
(test-equal "deployment request plugins preserve names"
|
||||||
'("aether")
|
'("tribe-one-aether")
|
||||||
(deployment-request-plugins
|
(deployment-request-plugins
|
||||||
'(("schemaVersion" . "1")
|
'(("schema_version" . "1")
|
||||||
("action" . "apply")
|
("action" . "apply")
|
||||||
("plugins" . ("aether")))))
|
("plugins" . ("tribe-one-aether")))))
|
||||||
|
|
||||||
(test-equal "host config plugins are updated in tribes block"
|
(test-equal "host config plugins are updated in tribes block"
|
||||||
'(("schemaVersion" . "1")
|
'(("schema_version" . "1")
|
||||||
("tribes" . (("host" . "example.com")
|
("tribes" . (("host" . "example.com")
|
||||||
("plugins" . ("aether"))
|
("plugins" . ("tribe-one-aether"))
|
||||||
("disabledPlugins" . ())))
|
("disabled_plugins" . ())))
|
||||||
("edge" . (("certificateName" . "tribes"))))
|
("edge" . (("certificate_name" . "tribes"))))
|
||||||
(host-config-with-plugins
|
(host-config-with-plugins
|
||||||
'(("schemaVersion" . "1")
|
'(("schema_version" . "1")
|
||||||
("tribes" . (("host" . "example.com")
|
("tribes" . (("host" . "example.com")
|
||||||
("plugins" . ())))
|
("plugins" . ())))
|
||||||
("edge" . (("certificateName" . "tribes"))))
|
("edge" . (("certificate_name" . "tribes"))))
|
||||||
'("aether")))
|
'("tribe-one-aether")))
|
||||||
|
|
||||||
(test-equal "system target plugin names include installed plugins"
|
(test-equal "system target plugin names include installed plugins"
|
||||||
'("aether" "disabled")
|
'("disabled" "tribe-one-aether")
|
||||||
(system-target-plugin-names
|
(system-target-plugin-names
|
||||||
'(("plugins" . ((("plugin_name" . "aether")
|
'(("plugins" . ((("plugin_name" . "tribe-one-aether")
|
||||||
("enabled" . #t))
|
("enabled" . #t))
|
||||||
(("plugin_name" . "disabled")
|
(("plugin_name" . "disabled")
|
||||||
("enabled" . #f)))))))
|
("enabled" . #f)))))))
|
||||||
@@ -73,7 +74,7 @@
|
|||||||
(test-equal "system target disabled plugin names include disabled plugins"
|
(test-equal "system target disabled plugin names include disabled plugins"
|
||||||
'("disabled")
|
'("disabled")
|
||||||
(system-target-disabled-plugin-names
|
(system-target-disabled-plugin-names
|
||||||
'(("plugins" . ((("plugin_name" . "aether")
|
'(("plugins" . ((("plugin_name" . "tribe-one-aether")
|
||||||
("enabled" . #t))
|
("enabled" . #t))
|
||||||
(("plugin_name" . "disabled")
|
(("plugin_name" . "disabled")
|
||||||
("enabled" . #f)))))))
|
("enabled" . #f)))))))
|
||||||
@@ -101,7 +102,7 @@
|
|||||||
guix-tribes-runtime-missing-capabilities)
|
guix-tribes-runtime-missing-capabilities)
|
||||||
|
|
||||||
(test-equal "resolve-target emits channel-aware plugin package refs"
|
(test-equal "resolve-target emits channel-aware plugin package refs"
|
||||||
'("aether")
|
'("tribe-one-aether")
|
||||||
(let* ((plan (resolve-target valid-target))
|
(let* ((plan (resolve-target valid-target))
|
||||||
(hash-value (json-ref plan "plan_hash"))
|
(hash-value (json-ref plan "plan_hash"))
|
||||||
(resolved-plugins
|
(resolved-plugins
|
||||||
@@ -119,7 +120,7 @@
|
|||||||
(plan-plugins plan)))
|
(plan-plugins plan)))
|
||||||
|
|
||||||
(test-equal "resolve-target accepts spaced introduction fingerprints"
|
(test-equal "resolve-target accepts spaced introduction fingerprints"
|
||||||
'("sender")
|
'("tribe-one-sender")
|
||||||
(let* ((spaced-channel
|
(let* ((spaced-channel
|
||||||
`(("id" . "guix-tribes")
|
`(("id" . "guix-tribes")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
@@ -134,29 +135,29 @@
|
|||||||
(resolve-target
|
(resolve-target
|
||||||
`(("trusted_signers" . (,valid-signer))
|
`(("trusted_signers" . (,valid-signer))
|
||||||
("channels" . (,spaced-channel))
|
("channels" . (,spaced-channel))
|
||||||
("plugins" . ((("plugin_name" . "sender")
|
("plugins" . ((("plugin_name" . "tribe-one-sender")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
("enabled" . #t))))))))
|
("enabled" . #t))))))))
|
||||||
(plan-plugins plan)))
|
(plan-plugins plan)))
|
||||||
|
|
||||||
(test-equal "resolve-target satisfies org.tribe-one.caps.ui@1 from built-in Tribes UI"
|
(test-equal "resolve-target satisfies org.tribe-one.caps.ui@1 from built-in Tribes UI"
|
||||||
'("sender")
|
'("tribe-one-sender")
|
||||||
(let ((plan
|
(let ((plan
|
||||||
(resolve-target
|
(resolve-target
|
||||||
`(("trusted_signers" . (,valid-signer))
|
`(("trusted_signers" . (,valid-signer))
|
||||||
("channels" . (,valid-channel))
|
("channels" . (,valid-channel))
|
||||||
("plugins" . ((("plugin_name" . "sender")
|
("plugins" . ((("plugin_name" . "tribe-one-sender")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
("enabled" . #t))))))))
|
("enabled" . #t))))))))
|
||||||
(plan-plugins plan)))
|
(plan-plugins plan)))
|
||||||
|
|
||||||
(test-equal "resolve-target keeps disabled plugins installed but runtime-disabled"
|
(test-equal "resolve-target keeps disabled plugins installed but runtime-disabled"
|
||||||
'(("aether") ("aether"))
|
'(("tribe-one-aether") ("tribe-one-aether"))
|
||||||
(let ((plan
|
(let ((plan
|
||||||
(resolve-target
|
(resolve-target
|
||||||
`(("trusted_signers" . (,valid-signer))
|
`(("trusted_signers" . (,valid-signer))
|
||||||
("channels" . (,valid-channel))
|
("channels" . (,valid-channel))
|
||||||
("plugins" . ((("plugin_name" . "aether")
|
("plugins" . ((("plugin_name" . "tribe-one-aether")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
("enabled" . #f))))))))
|
("enabled" . #f))))))))
|
||||||
(list (plan-plugins plan) (plan-disabled-plugins plan))))
|
(list (plan-plugins plan) (plan-disabled-plugins plan))))
|
||||||
@@ -167,8 +168,8 @@
|
|||||||
(resolve-target
|
(resolve-target
|
||||||
`(("trusted_signers" . (,valid-signer))
|
`(("trusted_signers" . (,valid-signer))
|
||||||
("channels" . (,valid-channel))
|
("channels" . (,valid-channel))
|
||||||
("plugins" . ((("plugin_name" . "aether") ("enabled" . #t))
|
("plugins" . ((("plugin_name" . "tribe-one-aether") ("enabled" . #t))
|
||||||
(("plugin_name" . "aether") ("enabled" . #t))))))))
|
(("plugin_name" . "tribe-one-aether") ("enabled" . #t))))))))
|
||||||
|
|
||||||
(test-equal "resolve-target rejects unknown plugins"
|
(test-equal "resolve-target rejects unknown plugins"
|
||||||
"manifest_invalid"
|
"manifest_invalid"
|
||||||
@@ -193,8 +194,10 @@
|
|||||||
("allowed_signer_ids" . ("signer-1"))
|
("allowed_signer_ids" . ("signer-1"))
|
||||||
("introduction" . (("commit" . "intro123")
|
("introduction" . (("commit" . "intro123")
|
||||||
("fingerprint" . "0123456789ABCDEF0123456789ABCDEF01234567"))))))
|
("fingerprint" . "0123456789ABCDEF0123456789ABCDEF01234567"))))))
|
||||||
("plugins" . ((("plugin_name" . "aether")
|
("plugins" . ((("plugin_name" . "tribe-one-aether")
|
||||||
("channel_id" . "guix-tribes")
|
("channel_id" . "guix-tribes")
|
||||||
("enabled" . #t))))))))
|
("enabled" . #t))))))))
|
||||||
|
|
||||||
(test-end "tribes-deploy-executor"))
|
(test-end "tribes-deploy-executor"))
|
||||||
|
|
||||||
|
(run-tests-when-script "tests/tribes-deploy-executor.scm" run-tests)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#:use-module (tribes deploy config)
|
#:use-module (tribes deploy config)
|
||||||
#:use-module (tribes deploy executor)
|
#:use-module (tribes deploy executor)
|
||||||
#:use-module (tribes deploy guix-helper)
|
#:use-module (tribes deploy guix-helper)
|
||||||
|
#:use-module (tribes deploy handlers)
|
||||||
#:use-module (tribes deploy json)
|
#:use-module (tribes deploy json)
|
||||||
#:use-module (tribes deploy operations)
|
#:use-module (tribes deploy operations)
|
||||||
#:use-module (tribes deploy plan)
|
#:use-module (tribes deploy plan)
|
||||||
@@ -19,16 +20,16 @@
|
|||||||
|
|
||||||
(define plan-a
|
(define plan-a
|
||||||
'(("plan_hash" . "plan-a")
|
'(("plan_hash" . "plan-a")
|
||||||
("resolved_plugins" . ((("name" . "aether"))))))
|
("resolved_plugins" . ((("name" . "tribe-one-aether"))))))
|
||||||
|
|
||||||
(define plan-b
|
(define plan-b
|
||||||
'(("plan_hash" . "plan-b")
|
'(("plan_hash" . "plan-b")
|
||||||
("resolved_plugins" . ((("name" . "aether"))))))
|
("resolved_plugins" . ((("name" . "tribe-one-aether"))))))
|
||||||
|
|
||||||
(define plan-without-channel-delta
|
(define plan-without-channel-delta
|
||||||
'(("plan_hash" . "plan-without-channel-delta")
|
'(("plan_hash" . "plan-without-channel-delta")
|
||||||
("resolved_channels" . #())
|
("resolved_channels" . #())
|
||||||
("resolved_plugins" . ((("name" . "supertest"))))))
|
("resolved_plugins" . ((("name" . "tribe-one-supertest"))))))
|
||||||
|
|
||||||
(define plan-with-channel-pin
|
(define plan-with-channel-pin
|
||||||
'(("plan_hash" . "plan-with-channel-pin")
|
'(("plan_hash" . "plan-with-channel-pin")
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
("branch" . "master")
|
("branch" . "master")
|
||||||
("commit" . "abc123")
|
("commit" . "abc123")
|
||||||
("position" . 10))))
|
("position" . 10))))
|
||||||
("resolved_plugins" . ((("name" . "supertest"))))))
|
("resolved_plugins" . ((("name" . "tribe-one-supertest"))))))
|
||||||
(define plan-with-branch-channel
|
(define plan-with-branch-channel
|
||||||
'(("plan_hash" . "plan-with-branch-channel")
|
'(("plan_hash" . "plan-with-branch-channel")
|
||||||
("resolved_channels" . #((("channel_id" . "guix-tribes")
|
("resolved_channels" . #((("channel_id" . "guix-tribes")
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
("branch" . "master")
|
("branch" . "master")
|
||||||
("commit" . #f)
|
("commit" . #f)
|
||||||
("position" . 10))))
|
("position" . 10))))
|
||||||
("resolved_plugins" . ((("name" . "supertest"))))))
|
("resolved_plugins" . ((("name" . "tribe-one-supertest"))))))
|
||||||
|
|
||||||
(define (delete-if-present path)
|
(define (delete-if-present path)
|
||||||
(when (false-if-exception (lstat path))
|
(when (false-if-exception (lstat path))
|
||||||
@@ -89,7 +90,7 @@
|
|||||||
(lambda (_cfg _on-frame)
|
(lambda (_cfg _on-frame)
|
||||||
(helper-success-result
|
(helper-success-result
|
||||||
'(("event" . "done")
|
'(("event" . "done")
|
||||||
("catalog" . (("schemaVersion" . "2") ("plugins" . #()))))))
|
("catalog" . (("schema_version" . "2") ("plugins" . #()))))))
|
||||||
(lambda (_cfg _on-frame)
|
(lambda (_cfg _on-frame)
|
||||||
(set! pull-count (+ pull-count 1))
|
(set! pull-count (+ pull-count 1))
|
||||||
(helper-success-result
|
(helper-success-result
|
||||||
@@ -171,7 +172,7 @@
|
|||||||
(ensure-directory store-directory)
|
(ensure-directory store-directory)
|
||||||
(ensure-directory current-system-directory)
|
(ensure-directory current-system-directory)
|
||||||
(write-json-file host-config-file
|
(write-json-file host-config-file
|
||||||
'(("schemaVersion" . "1")
|
'(("schema_version" . "1")
|
||||||
("tribes" . (("host" . "example.test")
|
("tribes" . (("host" . "example.test")
|
||||||
("plugins" . ())))))
|
("plugins" . ())))))
|
||||||
(call-with-output-file channels-file
|
(call-with-output-file channels-file
|
||||||
@@ -244,6 +245,33 @@
|
|||||||
(define (run-tests)
|
(define (run-tests)
|
||||||
(test-begin "tribes-deploy-operations")
|
(test-begin "tribes-deploy-operations")
|
||||||
|
|
||||||
|
(let* ((fixture (make-fixture))
|
||||||
|
(state (make-state-store (fixture->config fixture)))
|
||||||
|
(host-config-file (assq-ref fixture 'host-config-file)))
|
||||||
|
(write-json-file host-config-file
|
||||||
|
'(("schema_version" . "1")
|
||||||
|
("tribes" . (("host" . "example.test")
|
||||||
|
("service_group" . "root")))
|
||||||
|
("edge" . (("certificate_subjects" . ())))))
|
||||||
|
(chmod host-config-file #o600)
|
||||||
|
(call-with-values
|
||||||
|
(lambda ()
|
||||||
|
(handle-update-edge-identity
|
||||||
|
state
|
||||||
|
'(("node_host" . "node.example.test")
|
||||||
|
("certificate_subjects" . ("node.example.test")))))
|
||||||
|
(lambda (status _payload)
|
||||||
|
(let ((stat-after (stat host-config-file)))
|
||||||
|
(test-equal "edge identity update succeeds"
|
||||||
|
200 status)
|
||||||
|
(test-equal "edge identity update stores host config group-readable mode"
|
||||||
|
#o640
|
||||||
|
(stat:perms stat-after))
|
||||||
|
(test-equal "edge identity update preserves selected subjects"
|
||||||
|
'("node.example.test")
|
||||||
|
(json-string-list-ref (json-ref (read-json-file host-config-file) "edge")
|
||||||
|
"certificate_subjects"))))))
|
||||||
|
|
||||||
(let* ((fixture (make-fixture))
|
(let* ((fixture (make-fixture))
|
||||||
(config (fixture->config fixture))
|
(config (fixture->config fixture))
|
||||||
(channels-file (assq-ref fixture 'channels-file))
|
(channels-file (assq-ref fixture 'channels-file))
|
||||||
@@ -516,8 +544,8 @@
|
|||||||
(call-with-values
|
(call-with-values
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(resolve-deployment
|
(resolve-deployment
|
||||||
'(("plugins" . ((("plugin_name" . "aether") ("enabled" . #t))
|
'(("plugins" . ((("plugin_name" . "tribe-one-aether") ("enabled" . #t))
|
||||||
(("plugin_name" . "aether") ("enabled" . #t)))))))
|
(("plugin_name" . "tribe-one-aether") ("enabled" . #t)))))))
|
||||||
(lambda (status payload)
|
(lambda (status payload)
|
||||||
(test-equal "resolve-deployment returns 409 for explicit resolver errors"
|
(test-equal "resolve-deployment returns 409 for explicit resolver errors"
|
||||||
409 status)
|
409 status)
|
||||||
|
|||||||
+196
-17
@@ -1,5 +1,7 @@
|
|||||||
(define-module (tests tribes-system-node)
|
(define-module (tests tribes-system-node)
|
||||||
|
#:use-module (gnu packages databases)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services databases)
|
||||||
#:use-module (gnu services monitoring)
|
#:use-module (gnu services monitoring)
|
||||||
#:use-module (gnu services shepherd)
|
#:use-module (gnu services shepherd)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
@@ -8,6 +10,8 @@
|
|||||||
#:use-module (srfi srfi-13)
|
#:use-module (srfi srfi-13)
|
||||||
#:use-module (srfi srfi-64)
|
#:use-module (srfi srfi-64)
|
||||||
#:use-module (tests support)
|
#:use-module (tests support)
|
||||||
|
#:use-module (tribes config host)
|
||||||
|
#:use-module (tribes config system-facts)
|
||||||
#:use-module (tribes plugins sender)
|
#:use-module (tribes plugins sender)
|
||||||
#:use-module (tribes services chrony)
|
#:use-module (tribes services chrony)
|
||||||
#:use-module (tribes services haproxy)
|
#:use-module (tribes services haproxy)
|
||||||
@@ -21,14 +25,24 @@
|
|||||||
#:export (run-tests))
|
#:export (run-tests))
|
||||||
|
|
||||||
(define node-module (resolve-module '(tribes system node)))
|
(define node-module (resolve-module '(tribes system node)))
|
||||||
|
(define lego-module (resolve-module '(tribes services lego)))
|
||||||
(define chrony-module (resolve-module '(tribes services chrony)))
|
(define chrony-module (resolve-module '(tribes services chrony)))
|
||||||
(define haproxy-module (resolve-module '(tribes services haproxy)))
|
(define haproxy-module (resolve-module '(tribes services haproxy)))
|
||||||
(define logging-module (resolve-module '(tribes services logging)))
|
(define logging-module (resolve-module '(tribes services logging)))
|
||||||
|
(define materialize-module (resolve-module '(tribes system materialize)))
|
||||||
(define tribes-service-module (resolve-module '(tribes services tribes)))
|
(define tribes-service-module (resolve-module '(tribes services tribes)))
|
||||||
(define victoriametrics-module (resolve-module '(tribes services victoriametrics)))
|
(define victoriametrics-module (resolve-module '(tribes services victoriametrics)))
|
||||||
(define edge-cache-vcl-text (module-ref node-module 'edge-cache-vcl-text))
|
(define edge-cache-vcl-text (module-ref node-module 'edge-cache-vcl-text))
|
||||||
|
(define edge-bootstrap-certificate-activation
|
||||||
|
(module-ref node-module 'edge-bootstrap-certificate-activation))
|
||||||
|
(define subject-is-ip? (module-ref node-module 'subject-is-ip?))
|
||||||
|
(define subject-is-dns? (module-ref node-module 'subject-is-dns?))
|
||||||
|
(define subject->san-entry (module-ref node-module 'subject->san-entry))
|
||||||
(define edge-cache-vcl (module-ref node-module 'edge-cache-vcl))
|
(define edge-cache-vcl (module-ref node-module 'edge-cache-vcl))
|
||||||
(define edge-services (module-ref node-module 'edge-services))
|
(define edge-services (module-ref node-module 'edge-services))
|
||||||
|
(define public-ipv6-networking-services
|
||||||
|
(module-ref materialize-module 'public-ipv6-networking-services))
|
||||||
|
(define lego-common-arguments (module-ref lego-module 'lego-common-arguments))
|
||||||
(define chrony-shepherd-services
|
(define chrony-shepherd-services
|
||||||
(module-ref chrony-module 'chrony-shepherd-services))
|
(module-ref chrony-module 'chrony-shepherd-services))
|
||||||
(define haproxy-config-file (module-ref haproxy-module 'haproxy-config-file))
|
(define haproxy-config-file (module-ref haproxy-module 'haproxy-config-file))
|
||||||
@@ -36,6 +50,8 @@
|
|||||||
(module-ref logging-module 'tribes-system-logging-config-text))
|
(module-ref logging-module 'tribes-system-logging-config-text))
|
||||||
(define tribes-root-shepherd-services
|
(define tribes-root-shepherd-services
|
||||||
(module-ref tribes-service-module 'tribes-root-shepherd-services))
|
(module-ref tribes-service-module 'tribes-root-shepherd-services))
|
||||||
|
(define tribes-activation
|
||||||
|
(module-ref tribes-service-module 'tribes-activation))
|
||||||
(define tribes-profile-packages
|
(define tribes-profile-packages
|
||||||
(module-ref tribes-service-module 'tribes-profile-packages))
|
(module-ref tribes-service-module 'tribes-profile-packages))
|
||||||
(define tribes-sender-ffmpeg-package
|
(define tribes-sender-ffmpeg-package
|
||||||
@@ -62,6 +78,9 @@
|
|||||||
(contains? vcl ".connect_timeout = 1s;"))
|
(contains? vcl ".connect_timeout = 1s;"))
|
||||||
(test-assert "edge cache backend uses bounded first-byte timeout"
|
(test-assert "edge cache backend uses bounded first-byte timeout"
|
||||||
(contains? vcl ".first_byte_timeout = 5s;"))
|
(contains? vcl ".first_byte_timeout = 5s;"))
|
||||||
|
(test-assert "edge cache gives admin API requests longer backend timeouts"
|
||||||
|
(contains? vcl
|
||||||
|
"sub vcl_backend_fetch {\n if (bereq.url ~ \"^/api/admin/\") {\n set bereq.connect_timeout = 1s;\n set bereq.first_byte_timeout = 35s;\n set bereq.between_bytes_timeout = 35s;"))
|
||||||
(test-assert "edge cache retries only GET/HEAD 5xx backend responses"
|
(test-assert "edge cache retries only GET/HEAD 5xx backend responses"
|
||||||
(contains? vcl
|
(contains? vcl
|
||||||
"if ((bereq.method == \"GET\" || bereq.method == \"HEAD\") &&\n beresp.status >= 500 && beresp.status <= 599 &&\n bereq.retries < 5)"))
|
"if ((bereq.method == \"GET\" || bereq.method == \"HEAD\") &&\n beresp.status >= 500 && beresp.status <= 599 &&\n bereq.retries < 5)"))
|
||||||
@@ -83,10 +102,76 @@
|
|||||||
vcl
|
vcl
|
||||||
(plain-file-content rendered))))
|
(plain-file-content rendered))))
|
||||||
|
|
||||||
|
(test-assert "edge certificate accepts IPv4 subjects"
|
||||||
|
(subject-is-ip? "178.156.143.247"))
|
||||||
|
(test-assert "edge certificate accepts IPv6 subjects"
|
||||||
|
(subject-is-ip? "2a01:4ff:f0:63ba::73be"))
|
||||||
|
(test-assert "edge certificate accepts DNS subjects"
|
||||||
|
(subject-is-dns? "node1.example.test"))
|
||||||
|
(test-assert "edge certificate rejects invalid DNS subjects"
|
||||||
|
(not (subject-is-dns? "-node1.example.test")))
|
||||||
|
(test-equal "edge certificate renders IPv4 SAN entries"
|
||||||
|
"IP:178.156.143.247"
|
||||||
|
(subject->san-entry "178.156.143.247"))
|
||||||
|
(test-equal "edge certificate renders IPv6 SAN entries"
|
||||||
|
"IP:2a01:4ff:f0:63ba::73be"
|
||||||
|
(subject->san-entry "2a01:4ff:f0:63ba::73be"))
|
||||||
|
(test-equal "edge certificate renders DNS SAN entries"
|
||||||
|
"DNS:node1.example.test"
|
||||||
|
(subject->san-entry "node1.example.test"))
|
||||||
|
|
||||||
|
(let* ((host-config
|
||||||
|
(json-scm->tribes-host-configuration
|
||||||
|
'(("schema_version" . "1")
|
||||||
|
("tribes" . (("working_directory" . "/var/lib/tribes")
|
||||||
|
("service_user" . "tribes")
|
||||||
|
("service_group" . "tribes")
|
||||||
|
("host" . "203.0.113.10")
|
||||||
|
("listen_address" . "127.0.0.1")
|
||||||
|
("listen_port" . 4000)
|
||||||
|
("scheme" . "https")
|
||||||
|
("port" . 443)
|
||||||
|
("sync_host" . "203.0.113.10")
|
||||||
|
("sync_port" . 4413)
|
||||||
|
("sync_bind_address" . "0.0.0.0")))
|
||||||
|
("edge" . (("certificate_name" . "tribes")))
|
||||||
|
("network" . (("public_ipv6" . (("address" . "2001:db8::73be")
|
||||||
|
("prefix_length" . 64)
|
||||||
|
("gateway" . "fe80::1"))))))))
|
||||||
|
(public-ipv6 (tribes-host-configuration-public-ipv6 host-config))
|
||||||
|
(ipv6-services
|
||||||
|
(public-ipv6-networking-services
|
||||||
|
host-config
|
||||||
|
(tribes-system-facts
|
||||||
|
(host-name "node-a")
|
||||||
|
(interface "eth0")
|
||||||
|
(bootloader-targets '("/dev/sda"))
|
||||||
|
(boot-partition-uuid "00000000-0000-0000-0000-000000000001")
|
||||||
|
(root-luks-uuid "00000000-0000-0000-0000-000000000002")))))
|
||||||
|
(test-equal "host config parses static public IPv6 address"
|
||||||
|
"2001:db8::73be"
|
||||||
|
(tribes-public-ipv6-configuration-address public-ipv6))
|
||||||
|
(test-equal "host config parses static public IPv6 prefix length"
|
||||||
|
64
|
||||||
|
(tribes-public-ipv6-configuration-prefix-length public-ipv6))
|
||||||
|
(test-equal "host config parses static public IPv6 gateway"
|
||||||
|
"fe80::1"
|
||||||
|
(tribes-public-ipv6-configuration-gateway public-ipv6))
|
||||||
|
(test-assert "static public IPv6 renders a dedicated networking service"
|
||||||
|
(let ((text (object->string ipv6-services)))
|
||||||
|
(and (contains? text "tribes-public-ipv6-networking")
|
||||||
|
(contains? text "2001:db8::73be/64")
|
||||||
|
(contains? text "fe80::1")
|
||||||
|
(contains? text "eth0")))))
|
||||||
|
|
||||||
(let* ((config (tribes-node-configuration
|
(let* ((config (tribes-node-configuration
|
||||||
(tribes (tribes-configuration
|
(tribes (tribes-configuration
|
||||||
(host "example.invalid")))))
|
(host "example.invalid")))))
|
||||||
(services (tribes-node-services config))
|
(services (tribes-node-services config))
|
||||||
|
(postgresql-service
|
||||||
|
(find (lambda (service)
|
||||||
|
(eq? (service-kind service) postgresql-service-type))
|
||||||
|
services))
|
||||||
(chrony-service
|
(chrony-service
|
||||||
(find (lambda (service)
|
(find (lambda (service)
|
||||||
(eq? (service-kind service) chrony-service-type))
|
(eq? (service-kind service) chrony-service-type))
|
||||||
@@ -106,6 +191,9 @@
|
|||||||
services)))
|
services)))
|
||||||
(test-assert "node profile includes nftables for sync partition tests"
|
(test-assert "node profile includes nftables for sync partition tests"
|
||||||
network-tools-service)
|
network-tools-service)
|
||||||
|
(test-eq "node uses PostgreSQL 17"
|
||||||
|
postgresql-17
|
||||||
|
(postgresql-configuration-postgresql (service-value postgresql-service)))
|
||||||
(test-assert "node includes Chrony service"
|
(test-assert "node includes Chrony service"
|
||||||
chrony-service)
|
chrony-service)
|
||||||
(test-assert "node includes Prometheus node exporter service"
|
(test-assert "node includes Prometheus node exporter service"
|
||||||
@@ -249,9 +337,9 @@
|
|||||||
|
|
||||||
(let* ((config (tribes-node-configuration
|
(let* ((config (tribes-node-configuration
|
||||||
(tribes (tribes-configuration
|
(tribes (tribes-configuration
|
||||||
(host "example.invalid")))
|
(host "203.0.113.10")))
|
||||||
(edge (tribes-edge-configuration
|
(edge (tribes-edge-configuration
|
||||||
(certificate-email "ops@example.invalid")))))
|
(certificate-subjects '("203.0.113.10"))))))
|
||||||
(services (edge-services config))
|
(services (edge-services config))
|
||||||
(vinyl-service (find (lambda (service)
|
(vinyl-service (find (lambda (service)
|
||||||
(eq? (service-kind service) vinyl-service-type))
|
(eq? (service-kind service) vinyl-service-type))
|
||||||
@@ -270,8 +358,6 @@
|
|||||||
(service-value vinyl-service)))
|
(service-value vinyl-service)))
|
||||||
(vinyl-exporter-config (and vinyl-exporter-service
|
(vinyl-exporter-config (and vinyl-exporter-service
|
||||||
(service-value vinyl-exporter-service)))
|
(service-value vinyl-exporter-service)))
|
||||||
(lego-config (and lego-service
|
|
||||||
(service-value lego-service)))
|
|
||||||
(edge-vinyl (and vinyl-configs
|
(edge-vinyl (and vinyl-configs
|
||||||
(find (lambda (config)
|
(find (lambda (config)
|
||||||
(string=? (vinyl-configuration-name config)
|
(string=? (vinyl-configuration-name config)
|
||||||
@@ -307,20 +393,109 @@
|
|||||||
'((max_retries . 5))
|
'((max_retries . 5))
|
||||||
(and edge-vinyl
|
(and edge-vinyl
|
||||||
(vinyl-configuration-parameters edge-vinyl)))
|
(vinyl-configuration-parameters edge-vinyl)))
|
||||||
(test-equal "lego waits for haproxy challenge routing"
|
(test-equal "edge no longer starts lego for public ACME"
|
||||||
'(haproxy)
|
#f
|
||||||
(and lego-config
|
lego-service)
|
||||||
(lego-certificate-configuration-requirement
|
|
||||||
(car (lego-configuration-certificates lego-config)))))
|
|
||||||
(test-assert "edge uses haproxy for TLS termination"
|
(test-assert "edge uses haproxy for TLS termination"
|
||||||
haproxy-service))
|
haproxy-service))
|
||||||
|
|
||||||
|
(let* ((certificate (lego-certificate-configuration
|
||||||
|
(name "tribes")
|
||||||
|
(subjects '("203.0.113.10" "2001:db8::73be"))
|
||||||
|
(listen-http "127.0.0.1:8080")))
|
||||||
|
(args (lego-common-arguments certificate)))
|
||||||
|
(test-assert "lego HTTP challenge includes HTTP validation"
|
||||||
|
(member "--http" args))
|
||||||
|
(test-assert "lego HTTP challenge does not include DNS validation"
|
||||||
|
(not (member "--dns" args)))
|
||||||
|
(test-assert "lego HTTP challenge disables CN for IP identifiers"
|
||||||
|
(member "--disable-cn" args)))
|
||||||
|
|
||||||
|
(let* ((config (tribes-node-configuration
|
||||||
|
(tribes (tribes-configuration
|
||||||
|
(host "203.0.113.10")))
|
||||||
|
(edge (tribes-edge-configuration
|
||||||
|
(certificate-name "tribes")
|
||||||
|
(certificate-subjects
|
||||||
|
'("203.0.113.10" "2001:db8::73be"))))))
|
||||||
|
(services (edge-services config))
|
||||||
|
(lego-service (find (lambda (service)
|
||||||
|
(eq? (service-kind service) lego-service-type))
|
||||||
|
services))
|
||||||
|
(haproxy-service (find (lambda (service)
|
||||||
|
(eq? (service-kind service) haproxy-service-type))
|
||||||
|
services))
|
||||||
|
(haproxy-config (and haproxy-service
|
||||||
|
(service-value haproxy-service)))
|
||||||
|
(haproxy-text (and haproxy-config
|
||||||
|
(plain-file-content
|
||||||
|
(haproxy-config-file haproxy-config)))))
|
||||||
|
(test-equal "IP-only edge certificate does not create lego certificates"
|
||||||
|
#f
|
||||||
|
lego-service)
|
||||||
|
(test-equal "IP-only edge passes Tribes-managed cert to haproxy"
|
||||||
|
'("/var/lib/tribes/acme/edge.full.pem")
|
||||||
|
(haproxy-configuration-pem-files haproxy-config))
|
||||||
|
(test-assert "IP-only edge renders one bind with one cert"
|
||||||
|
(contains? haproxy-text
|
||||||
|
"bind 0.0.0.0:443 ssl crt /var/lib/tribes/acme/edge.full.pem alpn h2,http/1.1")))
|
||||||
|
|
||||||
|
(let* ((activation
|
||||||
|
(object->string
|
||||||
|
(gexp->approximate-sexp
|
||||||
|
(tribes-activation (tribes-configuration
|
||||||
|
(user "tribes")
|
||||||
|
(group "tribes")))))))
|
||||||
|
(test-assert "Tribes activation makes host config readable by service group"
|
||||||
|
(and (contains? activation "(chown host-config-file 0 gid)")
|
||||||
|
(contains? activation "(chmod host-config-file 416)"))))
|
||||||
|
|
||||||
|
(let* ((activation-service
|
||||||
|
(edge-bootstrap-certificate-activation
|
||||||
|
(tribes-edge-configuration
|
||||||
|
(certificate-subjects '("203.0.113.10")))
|
||||||
|
(tribes-configuration
|
||||||
|
(user "tribes")
|
||||||
|
(group "tribes")
|
||||||
|
(host "203.0.113.10"))))
|
||||||
|
(activation-text
|
||||||
|
(object->string
|
||||||
|
(gexp->approximate-sexp (service-value activation-service)))))
|
||||||
|
(test-assert "edge ACME activation gives Tribes ownership of state dir"
|
||||||
|
(and (contains? activation-text "(getpwnam \"tribes\")")
|
||||||
|
(contains? activation-text "(getgrnam \"tribes\")")
|
||||||
|
(contains? activation-text
|
||||||
|
"(chown \"/var/lib/tribes/acme\" uid gid)")
|
||||||
|
(contains? activation-text
|
||||||
|
"(chown \"/var/lib/tribes/acme/edge.key\" uid gid)"))))
|
||||||
|
|
||||||
|
(let* ((host-config
|
||||||
|
(json-scm->tribes-host-configuration
|
||||||
|
'(("schema_version" . "1")
|
||||||
|
("tribes" . (("working_directory" . "/var/lib/tribes")
|
||||||
|
("service_user" . "tribes")
|
||||||
|
("service_group" . "tribes")
|
||||||
|
("host" . "203.0.113.10")
|
||||||
|
("listen_address" . "127.0.0.1")
|
||||||
|
("listen_port" . 4000)
|
||||||
|
("scheme" . "https")
|
||||||
|
("port" . 443)
|
||||||
|
("sync_host" . "127.0.0.1")
|
||||||
|
("sync_port" . 4848)
|
||||||
|
("sync_bind_address" . "127.0.0.1")))
|
||||||
|
("edge" . (("certificate_name" . "tribes")
|
||||||
|
("certificate_subjects" . ("203.0.113.10" "2001:db8::73be")))))))
|
||||||
|
(edge (tribes-host-configuration-edge host-config)))
|
||||||
|
(test-equal "host config parses IP certificate subjects"
|
||||||
|
'("203.0.113.10" "2001:db8::73be")
|
||||||
|
(tribes-edge-configuration-certificate-subjects edge)))
|
||||||
|
|
||||||
(let* ((config (haproxy-configuration
|
(let* ((config (haproxy-configuration
|
||||||
(backend "127.0.0.1:6081")
|
(backend "127.0.0.1:6081")
|
||||||
(frontends '("0.0.0.0:443" "[::]:443 v6only"))
|
(frontends '("0.0.0.0:443" "[::]:443 v6only"))
|
||||||
(http-frontends '("0.0.0.0:80" "[::]:80 v6only"))
|
(http-frontends '("0.0.0.0:80" "[::]:80 v6only"))
|
||||||
(acme-backend "127.0.0.1:8080")
|
(acme-backend "127.0.0.1:8080")
|
||||||
(pem-files '("/var/lib/lego/tribes/full.pem"))))
|
(pem-files '("/var/lib/tribes/acme/edge.full.pem"))))
|
||||||
(rendered (haproxy-config-file config))
|
(rendered (haproxy-config-file config))
|
||||||
(text (plain-file-content rendered)))
|
(text (plain-file-content rendered)))
|
||||||
(test-equal "haproxy renders expected configuration file name"
|
(test-equal "haproxy renders expected configuration file name"
|
||||||
@@ -332,26 +507,30 @@
|
|||||||
(not (contains? text "limited-quic")))
|
(not (contains? text "limited-quic")))
|
||||||
(test-assert "haproxy logs to syslog-ng"
|
(test-assert "haproxy logs to syslog-ng"
|
||||||
(contains? text "log /dev/log local0"))
|
(contains? text "log /dev/log local0"))
|
||||||
|
(test-assert "haproxy preserves privileged bind capability for QUIC"
|
||||||
|
(contains? text "setcap cap_net_bind_service"))
|
||||||
(test-assert "haproxy binds configured certificate"
|
(test-assert "haproxy binds configured certificate"
|
||||||
(contains? text
|
(contains? text
|
||||||
"bind 0.0.0.0:443 ssl crt /var/lib/lego/tribes/full.pem alpn h2,http/1.1"))
|
"bind 0.0.0.0:443 ssl crt /var/lib/tribes/acme/edge.full.pem alpn h2,http/1.1"))
|
||||||
(test-assert "haproxy binds QUIC over IPv4"
|
(test-assert "haproxy binds QUIC over IPv4"
|
||||||
(contains? text
|
(contains? text
|
||||||
"bind quic4@0.0.0.0:443 ssl crt /var/lib/lego/tribes/full.pem alpn h3"))
|
"bind quic4@0.0.0.0:443 ssl crt /var/lib/tribes/acme/edge.full.pem alpn h3"))
|
||||||
(test-assert "haproxy binds QUIC over IPv6"
|
(test-assert "haproxy binds QUIC over IPv6"
|
||||||
(contains? text
|
(contains? text
|
||||||
"bind quic6@[::]:443 v6only ssl crt /var/lib/lego/tribes/full.pem alpn h3"))
|
"bind quic6@[::]:443 v6only ssl crt /var/lib/tribes/acme/edge.full.pem alpn h3"))
|
||||||
(test-assert "haproxy advertises HTTP/3"
|
(test-assert "haproxy advertises HTTP/3"
|
||||||
(contains? text "http-response set-header alt-svc 'h3=\":443\"; ma=86400'"))
|
(contains? text "http-response set-header alt-svc 'h3=\":443\"; ma=86400'"))
|
||||||
|
(test-assert "haproxy owns public HSTS"
|
||||||
|
(contains? text "http-response set-header strict-transport-security \"max-age=31536000\""))
|
||||||
(test-assert "haproxy binds public HTTP"
|
(test-assert "haproxy binds public HTTP"
|
||||||
(contains? text "bind 0.0.0.0:80"))
|
(contains? text "bind 0.0.0.0:80"))
|
||||||
(test-assert "haproxy routes ACME challenges to lego"
|
(test-assert "haproxy routes ACME challenges to Tribes"
|
||||||
(contains? text "use_backend lego_acme if acme_challenge"))
|
(contains? text "use_backend tribes_acme if acme_challenge"))
|
||||||
(test-assert "haproxy redirects non-ACME HTTP traffic"
|
(test-assert "haproxy redirects non-ACME HTTP traffic"
|
||||||
(contains? text
|
(contains? text
|
||||||
"http-request redirect scheme https code 308 unless acme_challenge"))
|
"http-request redirect scheme https code 308 unless acme_challenge"))
|
||||||
(test-assert "haproxy forwards ACME requests to lego challenge server"
|
(test-assert "haproxy forwards ACME requests to Tribes"
|
||||||
(contains? text "server lego 127.0.0.1:8080"))
|
(contains? text "server tribes 127.0.0.1:8080"))
|
||||||
(test-assert "haproxy forwards to vinyl cache backend"
|
(test-assert "haproxy forwards to vinyl cache backend"
|
||||||
(contains? text "server vinyl 127.0.0.1:6081 check")))
|
(contains? text "server vinyl 127.0.0.1:6081 check")))
|
||||||
|
|
||||||
|
|||||||
@@ -3,26 +3,25 @@
|
|||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:export (cuirass-jobs))
|
#:export (cuirass-jobs))
|
||||||
|
|
||||||
|
;; Publishable artifacts: the debug Docker image and the Sender runtime pack.
|
||||||
|
;; Node operating-system closures and bootloader files are warmed by the
|
||||||
|
;; dedicated (tribes ci artifacts-substitutes) jobset instead.
|
||||||
(define (cuirass-jobs store arguments)
|
(define (cuirass-jobs store arguments)
|
||||||
(let ((tribes-commit (arguments->channel-commit arguments 'tribes)))
|
(let ((tribes-commit (arguments->channel-commit arguments 'tribes)))
|
||||||
(append-map
|
(append-map
|
||||||
(lambda (system)
|
(lambda (system)
|
||||||
(append
|
(list (artifact-job store
|
||||||
(list (artifact-job store
|
"tribes-debug-docker"
|
||||||
"tribes-debug-docker"
|
(lambda ()
|
||||||
(lambda ()
|
(tribes-debug-docker-image
|
||||||
(tribes-debug-docker-image
|
#:image-tag
|
||||||
#:image-tag
|
(if tribes-commit
|
||||||
(if tribes-commit
|
(string-append "tribes-guix-debug:"
|
||||||
(string-append "tribes-guix-debug:"
|
tribes-commit)
|
||||||
tribes-commit)
|
"tribes-guix-debug:latest")))
|
||||||
"tribes-guix-debug:latest")))
|
system)
|
||||||
system)
|
(artifact-job store
|
||||||
(artifact-job store
|
"tribes-sender-runtime"
|
||||||
"tribes-sender-runtime"
|
tribes-sender-runtime-pack
|
||||||
tribes-sender-runtime-pack
|
system)))
|
||||||
system))
|
|
||||||
(substitute-manifest-jobs store system)
|
|
||||||
(substitute-system-jobs store system)
|
|
||||||
(substitute-file-jobs store system)))
|
|
||||||
(arguments->systems arguments))))
|
(arguments->systems arguments))))
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
(define-module (tribes ci artifacts-substitutes)
|
||||||
|
#:use-module (tribes ci artifacts)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:export (cuirass-jobs))
|
||||||
|
|
||||||
|
;; Warm the substitute mirror with the closures of the real Tribes node
|
||||||
|
;; operating-systems and their bootloader files, so deployed nodes pull every
|
||||||
|
;; required store path from guix.tribe-one.org during `guix system
|
||||||
|
;; init'/reconfigure without depending on upstream availability. This is the
|
||||||
|
;; authoritative substitute set: it is computed from the very operating-systems
|
||||||
|
;; nodes materialize, so it cannot drift the way the hand-curated
|
||||||
|
;; manifests/substitutes/*.scm package lists did, and it transitively covers
|
||||||
|
;; everything the node closure contains -- including the operator toolkit now
|
||||||
|
;; carried in the node system profile and the upstream dependencies pulled in
|
||||||
|
;; while building the closure.
|
||||||
|
(define (cuirass-jobs store arguments)
|
||||||
|
(append-map
|
||||||
|
(lambda (system)
|
||||||
|
(append (substitute-system-jobs store system)
|
||||||
|
(substitute-file-jobs store system)))
|
||||||
|
(arguments->systems arguments)))
|
||||||
+53
-26
@@ -9,6 +9,7 @@
|
|||||||
#:use-module (gnu packages nss)
|
#:use-module (gnu packages nss)
|
||||||
#:use-module (gnu system)
|
#:use-module (gnu system)
|
||||||
#:use-module (guix build-system gnu)
|
#:use-module (guix build-system gnu)
|
||||||
|
#:use-module (guix channels)
|
||||||
#:use-module (guix derivations)
|
#:use-module (guix derivations)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix monads)
|
#:use-module (guix monads)
|
||||||
@@ -17,9 +18,6 @@
|
|||||||
#:use-module (guix scripts pack)
|
#:use-module (guix scripts pack)
|
||||||
#:use-module (guix store)
|
#:use-module (guix store)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (manifests substitutes base)
|
|
||||||
#:use-module (manifests substitutes installer)
|
|
||||||
#:use-module (manifests substitutes tribes-node)
|
|
||||||
#:use-module (nbde system build-host-kexec-installer)
|
#:use-module (nbde system build-host-kexec-installer)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (tribes ci substitutes)
|
#:use-module (tribes ci substitutes)
|
||||||
@@ -33,7 +31,7 @@
|
|||||||
artifact-job
|
artifact-job
|
||||||
arguments->systems
|
arguments->systems
|
||||||
arguments->channel-commit
|
arguments->channel-commit
|
||||||
substitute-manifest-jobs
|
substitute-channel-profile-jobs
|
||||||
substitute-system-jobs
|
substitute-system-jobs
|
||||||
substitute-file-jobs))
|
substitute-file-jobs))
|
||||||
|
|
||||||
@@ -173,7 +171,8 @@
|
|||||||
(file-exists? path))
|
(file-exists? path))
|
||||||
(copy-recursively path
|
(copy-recursively path
|
||||||
(string-append squashfs-root "/"
|
(string-append squashfs-root "/"
|
||||||
(basename path)))))
|
(basename path))
|
||||||
|
#:keep-mtime? #t)))
|
||||||
(delete-duplicates
|
(delete-duplicates
|
||||||
(append (list system boot-path)
|
(append (list system boot-path)
|
||||||
(read-lines "system-graph"))))
|
(read-lines "system-graph"))))
|
||||||
@@ -249,10 +248,55 @@
|
|||||||
(repository
|
(repository
|
||||||
(repository-field 'commit repository))))
|
(repository-field 'commit repository))))
|
||||||
|
|
||||||
(define %substitute-manifest-targets
|
(define (arguments->channels arguments)
|
||||||
`((base . ,base-manifest)
|
(filter-map sexp->channel (or (assoc-ref arguments 'channels) '())))
|
||||||
(installer . ,installer-manifest)
|
|
||||||
(tribes-node . ,tribes-node-manifest)))
|
(define (canonical-time-machine-channel channel)
|
||||||
|
;; Cuirass passes channel sexps whose URLs point at its pre-fetched
|
||||||
|
;; /gnu/store checkouts and whose introductions were dropped when Cuirass
|
||||||
|
;; created channel instances from those checkouts. That is correct for
|
||||||
|
;; evaluating custom jobs inside Cuirass, but it does not match the profile
|
||||||
|
;; computed by `guix time-machine -C channels.scm` on Legion installers,
|
||||||
|
;; where the channel URLs and introductions come from the public channel
|
||||||
|
;; file. Reconstruct those canonical fields while preserving the evaluated
|
||||||
|
;; commits.
|
||||||
|
(let* ((channel-name* (channel-name channel))
|
||||||
|
(canonical-url (match channel-name*
|
||||||
|
('guix "https://git.teralink.net/tribes/guix-fork.git")
|
||||||
|
('tribes "https://git.teralink.net/tribes/guix-tribes.git")
|
||||||
|
(_ (channel-url channel))))
|
||||||
|
(canonical-introduction
|
||||||
|
(or (channel-introduction channel)
|
||||||
|
(match channel-name*
|
||||||
|
('guix
|
||||||
|
(make-channel-introduction
|
||||||
|
"093f27dde01cdbda68f2ec4b81e5a34ae180aab9"
|
||||||
|
(openpgp-fingerprint
|
||||||
|
"6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3")))
|
||||||
|
('tribes
|
||||||
|
(make-channel-introduction
|
||||||
|
"607c69a5c1662acca07ad72c3e18646c73500856"
|
||||||
|
(openpgp-fingerprint
|
||||||
|
"6688 9153 C51C 4613 A493 A525 2F0D FD14 EF99 DAC3")))
|
||||||
|
(_ #f)))))
|
||||||
|
((@@ (guix channels) make-channel)
|
||||||
|
channel-name*
|
||||||
|
canonical-url
|
||||||
|
(channel-branch channel)
|
||||||
|
(channel-commit channel)
|
||||||
|
canonical-introduction
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
(define (substitute-channel-profile-jobs store arguments system)
|
||||||
|
(let ((channels (map canonical-time-machine-channel
|
||||||
|
(arguments->channels arguments))))
|
||||||
|
(if (null? channels)
|
||||||
|
'()
|
||||||
|
(list (artifact-job store
|
||||||
|
"substitute-channel-profile"
|
||||||
|
(lambda ()
|
||||||
|
(latest-channel-derivation channels))
|
||||||
|
system)))))
|
||||||
|
|
||||||
(define %substitute-file-targets
|
(define %substitute-file-targets
|
||||||
`((bios-bootloader-configuration . ,bios-bootloader-configuration)
|
`((bios-bootloader-configuration . ,bios-bootloader-configuration)
|
||||||
@@ -260,12 +304,6 @@
|
|||||||
(efi-bootloader-configuration . ,efi-bootloader-configuration)
|
(efi-bootloader-configuration . ,efi-bootloader-configuration)
|
||||||
(efi-bootloader-configuration-installer . ,efi-bootloader-configuration-installer)))
|
(efi-bootloader-configuration-installer . ,efi-bootloader-configuration-installer)))
|
||||||
|
|
||||||
(define (manifest-profile manifest)
|
|
||||||
(profile
|
|
||||||
(content manifest)
|
|
||||||
(hooks %default-profile-hooks)
|
|
||||||
(locales? #t)))
|
|
||||||
|
|
||||||
(define (artifact-job store name proc system)
|
(define (artifact-job store name proc system)
|
||||||
(let ((drv (parameterize ((%current-system system)
|
(let ((drv (parameterize ((%current-system system)
|
||||||
(%graft? #f))
|
(%graft? #f))
|
||||||
@@ -279,17 +317,6 @@
|
|||||||
#:max-silent-time 3600
|
#:max-silent-time 3600
|
||||||
#:timeout 72000)))
|
#:timeout 72000)))
|
||||||
|
|
||||||
(define (substitute-manifest-jobs store system)
|
|
||||||
(map (match-lambda
|
|
||||||
((name . manifest)
|
|
||||||
(artifact-job store
|
|
||||||
(string-append "substitute-manifest-"
|
|
||||||
(symbol->string name))
|
|
||||||
(lambda ()
|
|
||||||
(lower-object (manifest-profile manifest)))
|
|
||||||
system)))
|
|
||||||
%substitute-manifest-targets))
|
|
||||||
|
|
||||||
(define (substitute-system-jobs store system)
|
(define (substitute-system-jobs store system)
|
||||||
(map (match-lambda
|
(map (match-lambda
|
||||||
((name . os)
|
((name . os)
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
(define-module (tribes ci channel)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (tribes ci artifacts)
|
||||||
|
#:export (cuirass-jobs))
|
||||||
|
|
||||||
|
;; Cheap canary spec: emit only the channel-instance derivation, so a
|
||||||
|
;; "tribes modules compile and the checkout is reachable" signal is
|
||||||
|
;; independent of any package or system build.
|
||||||
|
(define (cuirass-jobs store arguments)
|
||||||
|
(append-map (lambda (system)
|
||||||
|
(substitute-channel-profile-jobs store arguments system))
|
||||||
|
(arguments->systems arguments)))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestLegionSharedBuilder legion@example.invalid
|
||||||
@@ -15,11 +15,13 @@
|
|||||||
#:use-module (nbde system initrd)
|
#:use-module (nbde system initrd)
|
||||||
#:use-module (nbde system mapped-devices)
|
#:use-module (nbde system mapped-devices)
|
||||||
#:use-module (tribes config host)
|
#:use-module (tribes config host)
|
||||||
|
#:use-module (tribes config system-facts)
|
||||||
#:use-module (tribes packages plugins)
|
#:use-module (tribes packages plugins)
|
||||||
#:use-module (tribes packages source)
|
#:use-module (tribes packages source)
|
||||||
#:use-module (tribes plugins registry)
|
#:use-module (tribes plugins registry)
|
||||||
#:use-module (tribes services tribes)
|
#:use-module (tribes services tribes)
|
||||||
#:use-module (tribes system installer)
|
#:use-module (tribes system installer)
|
||||||
|
#:use-module (tribes system materialize)
|
||||||
#:use-module (tribes system node)
|
#:use-module (tribes system node)
|
||||||
#:export (phase1-operating-system
|
#:export (phase1-operating-system
|
||||||
base-edge-operating-system
|
base-edge-operating-system
|
||||||
@@ -140,9 +142,8 @@
|
|||||||
(tribes (ci-tribes-configuration plugins))
|
(tribes (ci-tribes-configuration plugins))
|
||||||
(edge
|
(edge
|
||||||
(tribes-edge-configuration
|
(tribes-edge-configuration
|
||||||
(certificate-name "node1-example-invalid")
|
(certificate-name "203-0-113-10")
|
||||||
(certificate-subjects '("node1.example.invalid"))
|
(certificate-subjects '("203.0.113.10"))
|
||||||
(certificate-email "ops@example.invalid")
|
|
||||||
(certificate-profile "shortlived")
|
(certificate-profile "shortlived")
|
||||||
(renew-days 4)
|
(renew-days 4)
|
||||||
(http-port 80)
|
(http-port 80)
|
||||||
@@ -153,6 +154,25 @@
|
|||||||
(cache-port 6081)
|
(cache-port 6081)
|
||||||
(cache-storage '("malloc,256M"))))))
|
(cache-storage '("malloc,256M"))))))
|
||||||
|
|
||||||
|
(define (ci-authorized-keys-file-name)
|
||||||
|
(or (search-path %load-path "tribes/ci/fixtures/root-authorized_keys")
|
||||||
|
(error "failed to locate CI authorized_keys fixture")))
|
||||||
|
(define %ci-system-facts
|
||||||
|
(tribes-system-facts
|
||||||
|
(host-name "tribes-ci-base-edge")
|
||||||
|
(interface "eth0")
|
||||||
|
(boot-mode "bios")
|
||||||
|
(bootloader-targets (list "/dev/sda"))
|
||||||
|
(boot-partition-uuid "11111111-2222-3333-4444-555555555555")
|
||||||
|
(boot-partition-file-system-type "ext4")
|
||||||
|
(root-luks-uuid "66666666-7777-8888-9999-aaaaaaaaaaaa")
|
||||||
|
(root-mapper-name "cryptroot")
|
||||||
|
(root-file-system-type "ext4")
|
||||||
|
(authorized-keys-file (ci-authorized-keys-file-name))
|
||||||
|
(local-boot-key-file "/boot/nbde/local-boot.key")
|
||||||
|
(tang-port 7654)
|
||||||
|
(initrd-network-timeout-seconds 20)
|
||||||
|
(enable-bbr? #t)))
|
||||||
(define* (ci-operating-system name plugins
|
(define* (ci-operating-system name plugins
|
||||||
#:key
|
#:key
|
||||||
(bootloader
|
(bootloader
|
||||||
@@ -170,6 +190,10 @@
|
|||||||
#:interface "eth0"
|
#:interface "eth0"
|
||||||
#:authorized-keys-file %ci-authorized-keys-file
|
#:authorized-keys-file %ci-authorized-keys-file
|
||||||
#:extra-services %ci-nbde-services))
|
#:extra-services %ci-nbde-services))
|
||||||
|
(define (ci-materialized-operating-system plugins)
|
||||||
|
(tribes-host-configuration+system-facts->operating-system
|
||||||
|
(ci-host-configuration plugins)
|
||||||
|
%ci-system-facts))
|
||||||
|
|
||||||
(define* (bootloader-ci-operating-system name bootloader file-systems)
|
(define* (bootloader-ci-operating-system name bootloader file-systems)
|
||||||
(operating-system
|
(operating-system
|
||||||
@@ -228,24 +252,24 @@
|
|||||||
(ci-operating-system "tribes-ci-phase1" '()))
|
(ci-operating-system "tribes-ci-phase1" '()))
|
||||||
|
|
||||||
(define base-edge-operating-system
|
(define base-edge-operating-system
|
||||||
(ci-operating-system "tribes-ci-base-edge" '()))
|
(ci-materialized-operating-system '()))
|
||||||
|
|
||||||
(define aether-edge-operating-system
|
(define aether-edge-operating-system
|
||||||
(ci-operating-system "tribes-ci-aether-edge"
|
(ci-operating-system "tribes-ci-aether-edge"
|
||||||
(list (plugin-by-name "aether"))))
|
(list (plugin-by-name "tribe-one-aether"))))
|
||||||
|
|
||||||
(define kobold-edge-operating-system
|
(define kobold-edge-operating-system
|
||||||
(ci-operating-system "tribes-ci-kobold-edge"
|
(ci-operating-system "tribes-ci-kobold-edge"
|
||||||
(list (plugin-by-name "trust")
|
(list (plugin-by-name "tribe-one-trust")
|
||||||
(plugin-by-name "kobold"))))
|
(plugin-by-name "tribe-one-kobold"))))
|
||||||
|
|
||||||
(define sender-edge-operating-system
|
(define sender-edge-operating-system
|
||||||
(ci-operating-system "tribes-ci-sender-edge"
|
(ci-operating-system "tribes-ci-sender-edge"
|
||||||
(list (plugin-by-name "sender"))))
|
(list (plugin-by-name "tribe-one-sender"))))
|
||||||
|
|
||||||
(define supertest-edge-operating-system
|
(define supertest-edge-operating-system
|
||||||
(ci-operating-system "tribes-ci-supertest-edge"
|
(ci-operating-system "tribes-ci-supertest-edge"
|
||||||
(list (plugin-by-name "supertest"))))
|
(list (plugin-by-name "tribe-one-supertest"))))
|
||||||
|
|
||||||
(define %substitute-operating-system-targets
|
(define %substitute-operating-system-targets
|
||||||
`((phase1 . ,phase1-operating-system)
|
`((phase1 . ,phase1-operating-system)
|
||||||
|
|||||||
+74
-45
@@ -6,19 +6,35 @@
|
|||||||
#:use-module (tribes packages source)
|
#:use-module (tribes packages source)
|
||||||
#:use-module (tribes services tribes)
|
#:use-module (tribes services tribes)
|
||||||
#:use-module (tribes system node)
|
#:use-module (tribes system node)
|
||||||
#:export (tribes-host-configuration
|
#:export (tribes-public-ipv6-configuration
|
||||||
|
tribes-public-ipv6-configuration?
|
||||||
|
tribes-public-ipv6-configuration-address
|
||||||
|
tribes-public-ipv6-configuration-prefix-length
|
||||||
|
tribes-public-ipv6-configuration-gateway
|
||||||
|
tribes-host-configuration
|
||||||
tribes-host-configuration?
|
tribes-host-configuration?
|
||||||
tribes-host-configuration-tribes
|
tribes-host-configuration-tribes
|
||||||
tribes-host-configuration-edge
|
tribes-host-configuration-edge
|
||||||
|
tribes-host-configuration-public-ipv6
|
||||||
json-scm->tribes-host-configuration))
|
json-scm->tribes-host-configuration))
|
||||||
|
|
||||||
|
(define-record-type* <tribes-public-ipv6-configuration>
|
||||||
|
tribes-public-ipv6-configuration make-tribes-public-ipv6-configuration
|
||||||
|
tribes-public-ipv6-configuration?
|
||||||
|
(address tribes-public-ipv6-configuration-address)
|
||||||
|
(prefix-length tribes-public-ipv6-configuration-prefix-length
|
||||||
|
(default 64))
|
||||||
|
(gateway tribes-public-ipv6-configuration-gateway))
|
||||||
|
|
||||||
(define-record-type* <tribes-host-configuration>
|
(define-record-type* <tribes-host-configuration>
|
||||||
tribes-host-configuration make-tribes-host-configuration
|
tribes-host-configuration make-tribes-host-configuration
|
||||||
tribes-host-configuration?
|
tribes-host-configuration?
|
||||||
(tribes tribes-host-configuration-tribes
|
(tribes tribes-host-configuration-tribes
|
||||||
(default (tribes-configuration)))
|
(default (tribes-configuration)))
|
||||||
(edge tribes-host-configuration-edge
|
(edge tribes-host-configuration-edge
|
||||||
(default (tribes-edge-configuration))))
|
(default (tribes-edge-configuration)))
|
||||||
|
(public-ipv6 tribes-host-configuration-public-ipv6
|
||||||
|
(default #f)))
|
||||||
|
|
||||||
(define (json-object? value)
|
(define (json-object? value)
|
||||||
(and (list? value) (every pair? value)))
|
(and (list? value) (every pair? value)))
|
||||||
@@ -73,12 +89,25 @@
|
|||||||
(tribes-plugin-definition-external-plugin plugin-definition)))
|
(tribes-plugin-definition-external-plugin plugin-definition)))
|
||||||
plugin-names))
|
plugin-names))
|
||||||
|
|
||||||
|
(define (json-scm->public-ipv6-configuration payload)
|
||||||
|
(let ((network-json (json-ref payload "network")))
|
||||||
|
(and (json-object? network-json)
|
||||||
|
(let ((ipv6-json (json-ref network-json "public_ipv6")))
|
||||||
|
(and (json-object? ipv6-json)
|
||||||
|
(tribes-public-ipv6-configuration
|
||||||
|
(address
|
||||||
|
(required-string ipv6-json "address"))
|
||||||
|
(prefix-length
|
||||||
|
(optional-integer ipv6-json "prefix_length" 64))
|
||||||
|
(gateway
|
||||||
|
(required-string ipv6-json "gateway"))))))))
|
||||||
|
|
||||||
(define (json-scm->tribes-host-configuration payload)
|
(define (json-scm->tribes-host-configuration payload)
|
||||||
(unless (json-object? payload)
|
(unless (json-object? payload)
|
||||||
(error "host configuration must be a JSON object"))
|
(error "host configuration must be a JSON object"))
|
||||||
(unless (equal? (json-string-ref payload "schemaVersion") "1")
|
(unless (equal? (json-string-ref payload "schema_version") "1")
|
||||||
(error "unsupported host configuration schema version"
|
(error "unsupported host configuration schema version"
|
||||||
(json-ref payload "schemaVersion")))
|
(json-ref payload "schema_version")))
|
||||||
(let* ((tribes-json (json-ref payload "tribes"))
|
(let* ((tribes-json (json-ref payload "tribes"))
|
||||||
(edge-json (json-ref payload "edge"))
|
(edge-json (json-ref payload "edge"))
|
||||||
(tribes-defaults (tribes-configuration))
|
(tribes-defaults (tribes-configuration))
|
||||||
@@ -92,113 +121,113 @@
|
|||||||
(tribes-configuration
|
(tribes-configuration
|
||||||
(package tribes-package)
|
(package tribes-package)
|
||||||
(working-directory
|
(working-directory
|
||||||
(required-string tribes-json "workingDirectory"))
|
(required-string tribes-json "working_directory"))
|
||||||
(user
|
(user
|
||||||
(required-string tribes-json "serviceUser"))
|
(required-string tribes-json "service_user"))
|
||||||
(group
|
(group
|
||||||
(required-string tribes-json "serviceGroup"))
|
(required-string tribes-json "service_group"))
|
||||||
(host
|
(host
|
||||||
(required-string tribes-json "host"))
|
(required-string tribes-json "host"))
|
||||||
(listen-address
|
(listen-address
|
||||||
(required-string tribes-json "listenAddress"))
|
(required-string tribes-json "listen_address"))
|
||||||
(listen-port
|
(listen-port
|
||||||
(required-integer tribes-json "listenPort"))
|
(required-integer tribes-json "listen_port"))
|
||||||
(scheme
|
(scheme
|
||||||
(required-string tribes-json "scheme"))
|
(required-string tribes-json "scheme"))
|
||||||
(port
|
(port
|
||||||
(required-integer tribes-json "port"))
|
(required-integer tribes-json "port"))
|
||||||
(sync-host
|
(sync-host
|
||||||
(required-string tribes-json "syncHost"))
|
(required-string tribes-json "sync_host"))
|
||||||
(sync-port
|
(sync-port
|
||||||
(required-integer tribes-json "syncPort"))
|
(required-integer tribes-json "sync_port"))
|
||||||
(sync-bind-address
|
(sync-bind-address
|
||||||
(required-string tribes-json "syncBindAddress"))
|
(required-string tribes-json "sync_bind_address"))
|
||||||
(sync-url
|
(sync-url
|
||||||
(json-string-ref tribes-json "syncUrl"))
|
(json-string-ref tribes-json "sync_url"))
|
||||||
(sync-tls-certfile
|
(sync-tls-certfile
|
||||||
(json-string-ref tribes-json "syncTlsCertFile"))
|
(json-string-ref tribes-json "sync_tls_cert_file"))
|
||||||
(sync-tls-keyfile
|
(sync-tls-keyfile
|
||||||
(json-string-ref tribes-json "syncTlsKeyFile"))
|
(json-string-ref tribes-json "sync_tls_key_file"))
|
||||||
(sync-tls-cacertfile
|
(sync-tls-cacertfile
|
||||||
(json-string-ref tribes-json "syncTlsCaCertFile"))
|
(json-string-ref tribes-json "sync_tls_ca_cert_file"))
|
||||||
(host-manifest
|
(host-manifest
|
||||||
(json-string-ref tribes-json "hostManifest"))
|
(json-string-ref tribes-json "host_manifest"))
|
||||||
(admin-pubkeys
|
(admin-pubkeys
|
||||||
(optional-string-list tribes-json "adminPubkeys"
|
(optional-string-list tribes-json "admin_pubkeys"
|
||||||
(tribes-configuration-admin-pubkeys tribes-defaults)))
|
(tribes-configuration-admin-pubkeys tribes-defaults)))
|
||||||
(plugins
|
(plugins
|
||||||
(resolve-external-plugins
|
(resolve-external-plugins
|
||||||
(optional-string-list tribes-json "plugins" '())))
|
(optional-string-list tribes-json "plugins" '())))
|
||||||
(disabled-plugins
|
(disabled-plugins
|
||||||
(optional-string-list tribes-json "disabledPlugins" '()))
|
(optional-string-list tribes-json "disabled_plugins" '()))
|
||||||
(database-user
|
(database-user
|
||||||
(optional-string tribes-json "databaseUser"
|
(optional-string tribes-json "database_user"
|
||||||
(tribes-configuration-database-user tribes-defaults)))
|
(tribes-configuration-database-user tribes-defaults)))
|
||||||
(database-name
|
(database-name
|
||||||
(optional-string tribes-json "databaseName"
|
(optional-string tribes-json "database_name"
|
||||||
(tribes-configuration-database-name tribes-defaults)))
|
(tribes-configuration-database-name tribes-defaults)))
|
||||||
(parrhesia-database-name
|
(parrhesia-database-name
|
||||||
(optional-string tribes-json "parrhesiaDatabaseName"
|
(optional-string tribes-json "parrhesia_database_name"
|
||||||
(tribes-configuration-parrhesia-database-name tribes-defaults)))
|
(tribes-configuration-parrhesia-database-name tribes-defaults)))
|
||||||
(database-host
|
(database-host
|
||||||
(optional-string tribes-json "databaseHost"
|
(optional-string tribes-json "database_host"
|
||||||
(tribes-configuration-database-host tribes-defaults)))
|
(tribes-configuration-database-host tribes-defaults)))
|
||||||
(secret-key-base-file
|
(secret-key-base-file
|
||||||
(optional-string tribes-json "secretKeyBaseFile"
|
(optional-string tribes-json "secret_key_base_file"
|
||||||
(tribes-configuration-secret-key-base-file tribes-defaults)))
|
(tribes-configuration-secret-key-base-file tribes-defaults)))
|
||||||
(token-signing-secret-file
|
(token-signing-secret-file
|
||||||
(optional-string tribes-json "tokenSigningSecretFile"
|
(optional-string tribes-json "token_signing_secret_file"
|
||||||
(tribes-configuration-token-signing-secret-file tribes-defaults)))
|
(tribes-configuration-token-signing-secret-file tribes-defaults)))
|
||||||
(release-cookie-file
|
(release-cookie-file
|
||||||
(optional-string tribes-json "releaseCookieFile"
|
(optional-string tribes-json "release_cookie_file"
|
||||||
(tribes-configuration-release-cookie-file tribes-defaults)))
|
(tribes-configuration-release-cookie-file tribes-defaults)))
|
||||||
(release-distribution
|
(release-distribution
|
||||||
(optional-string tribes-json "releaseDistribution"
|
(optional-string tribes-json "release_distribution"
|
||||||
(tribes-configuration-release-distribution tribes-defaults)))
|
(tribes-configuration-release-distribution tribes-defaults)))
|
||||||
(release-node
|
(release-node
|
||||||
(json-string-ref tribes-json "releaseNode"))
|
(json-string-ref tribes-json "release_node"))
|
||||||
(dns-cluster-query
|
(dns-cluster-query
|
||||||
(json-string-ref tribes-json "dnsClusterQuery"))
|
(json-string-ref tribes-json "dns_cluster_query"))
|
||||||
(extra-environment-variables
|
(extra-environment-variables
|
||||||
(optional-string-list tribes-json "extraEnvironmentVariables"
|
(optional-string-list tribes-json "extra_environment_variables"
|
||||||
(tribes-configuration-extra-environment-variables
|
(tribes-configuration-extra-environment-variables
|
||||||
tribes-defaults)))
|
tribes-defaults)))
|
||||||
(log-file
|
(log-file
|
||||||
(optional-string tribes-json "logFile"
|
(optional-string tribes-json "log_file"
|
||||||
(tribes-configuration-log-file tribes-defaults)))))
|
(tribes-configuration-log-file tribes-defaults)))))
|
||||||
(edge
|
(edge
|
||||||
(tribes-edge-configuration
|
(tribes-edge-configuration
|
||||||
(certificate-name
|
(certificate-name
|
||||||
(required-string edge-json "certificateName"))
|
(required-string edge-json "certificate_name"))
|
||||||
(certificate-subjects
|
(certificate-subjects
|
||||||
(optional-string-list edge-json "certificateSubjects"
|
(optional-string-list edge-json "certificate_subjects"
|
||||||
(tribes-edge-configuration-certificate-subjects edge-defaults)))
|
(tribes-edge-configuration-certificate-subjects edge-defaults)))
|
||||||
(certificate-email
|
|
||||||
(required-string edge-json "certificateEmail"))
|
|
||||||
(certificate-profile
|
(certificate-profile
|
||||||
(optional-string edge-json "certificateProfile"
|
(optional-string edge-json "certificate_profile"
|
||||||
(tribes-edge-configuration-certificate-profile edge-defaults)))
|
(tribes-edge-configuration-certificate-profile edge-defaults)))
|
||||||
(renew-days
|
(renew-days
|
||||||
(optional-integer edge-json "renewDays"
|
(optional-integer edge-json "renew_days"
|
||||||
(tribes-edge-configuration-renew-days edge-defaults)))
|
(tribes-edge-configuration-renew-days edge-defaults)))
|
||||||
(http-port
|
(http-port
|
||||||
(optional-integer edge-json "httpPort"
|
(optional-integer edge-json "http_port"
|
||||||
(tribes-edge-configuration-http-port edge-defaults)))
|
(tribes-edge-configuration-http-port edge-defaults)))
|
||||||
(https-port
|
(https-port
|
||||||
(optional-integer edge-json "httpsPort"
|
(optional-integer edge-json "https_port"
|
||||||
(tribes-edge-configuration-https-port edge-defaults)))
|
(tribes-edge-configuration-https-port edge-defaults)))
|
||||||
(challenge-address
|
(challenge-address
|
||||||
(optional-string edge-json "challengeAddress"
|
(optional-string edge-json "challenge_address"
|
||||||
(tribes-edge-configuration-challenge-address edge-defaults)))
|
(tribes-edge-configuration-challenge-address edge-defaults)))
|
||||||
(challenge-port
|
(challenge-port
|
||||||
(optional-integer edge-json "challengePort"
|
(optional-integer edge-json "challenge_port"
|
||||||
(tribes-edge-configuration-challenge-port edge-defaults)))
|
(tribes-edge-configuration-challenge-port edge-defaults)))
|
||||||
(cache-address
|
(cache-address
|
||||||
(optional-string edge-json "cacheAddress"
|
(optional-string edge-json "cache_address"
|
||||||
(tribes-edge-configuration-cache-address edge-defaults)))
|
(tribes-edge-configuration-cache-address edge-defaults)))
|
||||||
(cache-port
|
(cache-port
|
||||||
(optional-integer edge-json "cachePort"
|
(optional-integer edge-json "cache_port"
|
||||||
(tribes-edge-configuration-cache-port edge-defaults)))
|
(tribes-edge-configuration-cache-port edge-defaults)))
|
||||||
(cache-storage
|
(cache-storage
|
||||||
(optional-string-list edge-json "cacheStorage"
|
(optional-string-list edge-json "cache_storage"
|
||||||
(tribes-edge-configuration-cache-storage edge-defaults))))))))
|
(tribes-edge-configuration-cache-storage edge-defaults)))))
|
||||||
|
(public-ipv6
|
||||||
|
(json-scm->public-ipv6-configuration payload)))))
|
||||||
|
|||||||
+173
-2
@@ -1,6 +1,7 @@
|
|||||||
(define-module (tribes deploy handlers)
|
(define-module (tribes deploy handlers)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
|
#:use-module (ice-9 textual-ports)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (tribes deploy channel-updates)
|
#:use-module (tribes deploy channel-updates)
|
||||||
#:use-module (tribes deploy config)
|
#:use-module (tribes deploy config)
|
||||||
@@ -18,12 +19,16 @@
|
|||||||
handle-commit
|
handle-commit
|
||||||
handle-rollback
|
handle-rollback
|
||||||
handle-abort
|
handle-abort
|
||||||
|
handle-install-edge-certificate
|
||||||
|
handle-update-edge-identity
|
||||||
error-payload
|
error-payload
|
||||||
validate-channel-updates-input
|
validate-channel-updates-input
|
||||||
validate-resolve-input
|
validate-resolve-input
|
||||||
validate-prepare-input
|
validate-prepare-input
|
||||||
validate-commit-input
|
validate-commit-input
|
||||||
validate-rollback-input))
|
validate-rollback-input
|
||||||
|
validate-install-edge-certificate-input
|
||||||
|
validate-update-edge-identity-input))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Validation — applied before dispatching to operations.scm.
|
;; Validation — applied before dispatching to operations.scm.
|
||||||
@@ -93,8 +98,32 @@
|
|||||||
"rollback payload is missing store_path")
|
"rollback payload is missing store_path")
|
||||||
(else #f)))
|
(else #f)))
|
||||||
|
|
||||||
|
(define (validate-install-edge-certificate-input payload)
|
||||||
|
(cond
|
||||||
|
((not (json-object-with-string-keys? payload))
|
||||||
|
"certificate install payload must be a JSON object")
|
||||||
|
((not (string? (or (json-ref payload "fullchain_path")
|
||||||
|
(json-ref payload "fullchainPath"))))
|
||||||
|
"certificate install payload is missing fullchain_path")
|
||||||
|
((not (string? (or (json-ref payload "private_key_path")
|
||||||
|
(json-ref payload "privateKeyPath"))))
|
||||||
|
"certificate install payload is missing private_key_path")
|
||||||
|
(else #f)))
|
||||||
|
|
||||||
|
(define (validate-update-edge-identity-input payload)
|
||||||
|
(let ((subjects (or (json-string-list-ref payload "certificate_subjects")
|
||||||
|
(json-string-list-ref payload "certificate_subjects"))))
|
||||||
|
(cond
|
||||||
|
((not (json-object-with-string-keys? payload))
|
||||||
|
"edge identity payload must be a JSON object")
|
||||||
|
((not (string? (edge-identity-public-host payload)))
|
||||||
|
"edge identity payload is missing public host candidates")
|
||||||
|
((not (and subjects (pair? subjects)))
|
||||||
|
"edge identity payload requires non-empty certificate_subjects")
|
||||||
|
(else #f))))
|
||||||
|
|
||||||
(define (error-payload code reason . details)
|
(define (error-payload code reason . details)
|
||||||
`(("schemaVersion" . "2")
|
`(("schema_version" . "2")
|
||||||
("ok" . #f)
|
("ok" . #f)
|
||||||
("status" . "failed")
|
("status" . "failed")
|
||||||
("code" . ,code)
|
("code" . ,code)
|
||||||
@@ -159,5 +188,147 @@
|
|||||||
(json-ref payload "target_plan"))))
|
(json-ref payload "target_plan"))))
|
||||||
(submit-rollback! state worker helper store-path plan))))))
|
(submit-rollback! state worker helper store-path plan))))))
|
||||||
|
|
||||||
|
(define (present-string value)
|
||||||
|
(and (string? value)
|
||||||
|
(> (string-length value) 0)
|
||||||
|
value))
|
||||||
|
|
||||||
|
(define (edge-identity-public-host payload)
|
||||||
|
(find present-string
|
||||||
|
(list (json-ref payload "public_host")
|
||||||
|
(json-ref payload "apex_host")
|
||||||
|
(json-ref payload "node_host")
|
||||||
|
(json-ref payload "public_ipv4")
|
||||||
|
(json-ref payload "public_ipv6"))))
|
||||||
|
|
||||||
|
(define (edge-identity-certificate-subjects payload)
|
||||||
|
(or (json-string-list-ref payload "certificate_subjects")
|
||||||
|
'()))
|
||||||
|
|
||||||
|
(define (assoc-ref/default object key default)
|
||||||
|
(let ((value (json-ref object key)))
|
||||||
|
(if value value default)))
|
||||||
|
|
||||||
|
(define (same-string-list? left right)
|
||||||
|
(and (= (length left) (length right))
|
||||||
|
(every string=? left right)))
|
||||||
|
|
||||||
|
(define (preserve-file-owner-and-mode! path stat-before)
|
||||||
|
(when stat-before
|
||||||
|
(chown path (stat:uid stat-before) (stat:gid stat-before))
|
||||||
|
(chmod path (stat:perms stat-before))))
|
||||||
|
(define (set-host-config-owner-and-mode! path host-config stat-before)
|
||||||
|
(let* ((tribes-config (assoc-ref/default host-config "tribes" '()))
|
||||||
|
(service-group (or (json-ref tribes-config "service_group") "tribes"))
|
||||||
|
(group (and (string? service-group)
|
||||||
|
(false-if-exception (getgrnam service-group)))))
|
||||||
|
(if group
|
||||||
|
(begin
|
||||||
|
(false-if-exception (chown path 0 (group:gid group)))
|
||||||
|
(chmod path #o640))
|
||||||
|
(preserve-file-owner-and-mode! path stat-before))))
|
||||||
|
|
||||||
|
(define (schedule-tribes-restart!)
|
||||||
|
(match (primitive-fork)
|
||||||
|
(0
|
||||||
|
(sleep 1)
|
||||||
|
(primitive-exit
|
||||||
|
(if (zero? (system* "/run/current-system/profile/bin/herd"
|
||||||
|
"restart" "tribes"))
|
||||||
|
0
|
||||||
|
1)))
|
||||||
|
(_pid #t)))
|
||||||
|
|
||||||
|
(define (safe-acme-path? path)
|
||||||
|
(and (string? path)
|
||||||
|
(string-prefix? "/var/lib/tribes/acme/" path)
|
||||||
|
(not (string-contains path "/../"))
|
||||||
|
(not (string-suffix? "/.." path))))
|
||||||
|
|
||||||
|
(define (update-edge-identity! state payload)
|
||||||
|
(let* ((cfg (state-store-config state))
|
||||||
|
(host-config-file (deploy-config-host-config-file cfg))
|
||||||
|
(host-config (read-json-file host-config-file))
|
||||||
|
(stat-before (false-if-exception (stat host-config-file)))
|
||||||
|
(tribes-config (assoc-ref/default host-config "tribes" '()))
|
||||||
|
(edge-config (assoc-ref/default host-config "edge" '()))
|
||||||
|
(old-public-host (json-ref tribes-config "host"))
|
||||||
|
(old-sync-host (json-ref tribes-config "sync_host"))
|
||||||
|
(public-host (edge-identity-public-host payload))
|
||||||
|
(subjects (edge-identity-certificate-subjects payload))
|
||||||
|
(public-host-changed? (not (equal? old-public-host public-host)))
|
||||||
|
(subjects-changed?
|
||||||
|
(not (same-string-list?
|
||||||
|
(or (json-string-list-ref edge-config "certificate_subjects") '())
|
||||||
|
subjects)))
|
||||||
|
(updated-tribes
|
||||||
|
(let ((with-host (assoc-set tribes-config "host" public-host)))
|
||||||
|
(if (or (not old-sync-host)
|
||||||
|
(and (string? old-sync-host)
|
||||||
|
(string? old-public-host)
|
||||||
|
(string=? old-sync-host old-public-host)))
|
||||||
|
(assoc-set with-host "sync_host" public-host)
|
||||||
|
with-host)))
|
||||||
|
(updated-edge (assoc-set edge-config "certificate_subjects" subjects))
|
||||||
|
(updated-host-config
|
||||||
|
(assoc-set (assoc-set host-config "tribes" updated-tribes)
|
||||||
|
"edge" updated-edge)))
|
||||||
|
(atomic-write-json-file host-config-file updated-host-config)
|
||||||
|
(set-host-config-owner-and-mode! host-config-file updated-host-config stat-before)
|
||||||
|
(when public-host-changed?
|
||||||
|
(schedule-tribes-restart!))
|
||||||
|
`(("ok" . #t)
|
||||||
|
("public_host" . ,public-host)
|
||||||
|
("certificate_subjects" . ,subjects)
|
||||||
|
("public_host_changed" . ,public-host-changed?)
|
||||||
|
("certificate_subjects_changed" . ,subjects-changed?)
|
||||||
|
("tribes_restart_scheduled" . ,public-host-changed?))))
|
||||||
|
|
||||||
|
(define (handle-update-edge-identity state payload)
|
||||||
|
(let ((err (validate-update-edge-identity-input payload)))
|
||||||
|
(cond
|
||||||
|
(err (values 400 (error-payload "invalid_request" err)))
|
||||||
|
(else (values 200 (update-edge-identity! state payload))))))
|
||||||
|
|
||||||
|
(define (install-edge-certificate! fullchain-path private-key-path)
|
||||||
|
(let* ((target-dir "/var/lib/tribes/acme")
|
||||||
|
(target-pem (string-append target-dir "/edge.full.pem"))
|
||||||
|
(tmp-pem (string-append target-pem ".tmp")))
|
||||||
|
(unless (file-exists? target-dir)
|
||||||
|
(mkdir target-dir))
|
||||||
|
(chmod target-dir #o700)
|
||||||
|
(call-with-output-file tmp-pem
|
||||||
|
(lambda (port)
|
||||||
|
(display (call-with-input-file fullchain-path get-string-all) port)
|
||||||
|
(newline port)
|
||||||
|
(display (call-with-input-file private-key-path get-string-all) port)))
|
||||||
|
(chmod tmp-pem #o600)
|
||||||
|
(rename-file tmp-pem target-pem)
|
||||||
|
(zero? (system* "/run/current-system/profile/bin/herd" "reload" "haproxy"))))
|
||||||
|
|
||||||
|
(define (handle-install-edge-certificate payload)
|
||||||
|
(let ((err (validate-install-edge-certificate-input payload)))
|
||||||
|
(cond
|
||||||
|
(err (values 400 (error-payload "invalid_request" err)))
|
||||||
|
(else
|
||||||
|
(let ((fullchain-path (or (json-ref payload "fullchain_path")
|
||||||
|
(json-ref payload "fullchainPath")))
|
||||||
|
(private-key-path (or (json-ref payload "private_key_path")
|
||||||
|
(json-ref payload "privateKeyPath"))))
|
||||||
|
(cond
|
||||||
|
((not (and (safe-acme-path? fullchain-path)
|
||||||
|
(safe-acme-path? private-key-path)))
|
||||||
|
(values 400 (error-payload "invalid_request"
|
||||||
|
"certificate paths must be under /var/lib/tribes/acme")))
|
||||||
|
((not (and (file-exists? fullchain-path)
|
||||||
|
(file-exists? private-key-path)))
|
||||||
|
(values 400 (error-payload "invalid_request"
|
||||||
|
"certificate source files do not exist")))
|
||||||
|
((install-edge-certificate! fullchain-path private-key-path)
|
||||||
|
(values 200 '(("ok" . #t))))
|
||||||
|
(else
|
||||||
|
(values 500 (error-payload "install_failed"
|
||||||
|
"failed to reload haproxy after certificate install")))))))))
|
||||||
|
|
||||||
(define (handle-abort state worker)
|
(define (handle-abort state worker)
|
||||||
(values 200 (abort-prepare! state worker)))
|
(values 200 (abort-prepare! state worker)))
|
||||||
|
|||||||
+15
-1
@@ -120,7 +120,21 @@
|
|||||||
((POST . "/v1/deployment/abort")
|
((POST . "/v1/deployment/abort")
|
||||||
. ,(lambda (_request _body)
|
. ,(lambda (_request _body)
|
||||||
(call-with-values (lambda () (handle-abort state worker))
|
(call-with-values (lambda () (handle-abort state worker))
|
||||||
json-response)))))
|
json-response)))
|
||||||
|
((POST . "/v1/certificates/edge/install")
|
||||||
|
. ,(lambda (request body)
|
||||||
|
(with-json-body cfg request body
|
||||||
|
(lambda (payload)
|
||||||
|
(call-with-values
|
||||||
|
(lambda () (handle-install-edge-certificate payload))
|
||||||
|
json-response)))))
|
||||||
|
((POST . "/v1/edge/identity/update")
|
||||||
|
. ,(lambda (request body)
|
||||||
|
(with-json-body cfg request body
|
||||||
|
(lambda (payload)
|
||||||
|
(call-with-values
|
||||||
|
(lambda () (handle-update-edge-identity state payload))
|
||||||
|
json-response)))))))
|
||||||
|
|
||||||
(define (route-lookup table method path)
|
(define (route-lookup table method path)
|
||||||
(find (lambda (entry)
|
(find (lambda (entry)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
"tribes"
|
"tribes"
|
||||||
(assoc-set
|
(assoc-set
|
||||||
(assoc-set tribes-config "plugins" plugin-names)
|
(assoc-set tribes-config "plugins" plugin-names)
|
||||||
"disabledPlugins" disabled-plugins))))
|
"disabled_plugins" disabled-plugins))))
|
||||||
|
|
||||||
(define (system-target-plugin-names target)
|
(define (system-target-plugin-names target)
|
||||||
(let ((plugins (or (json-list-ref target "plugins") '())))
|
(let ((plugins (or (json-list-ref target "plugins") '())))
|
||||||
|
|||||||
@@ -33,9 +33,10 @@
|
|||||||
"CONFIG_X86_USER_SHADOW_STACK=y"))
|
"CONFIG_X86_USER_SHADOW_STACK=y"))
|
||||||
|
|
||||||
(define %tribes-linux-disabled-options
|
(define %tribes-linux-disabled-options
|
||||||
'(;; Headless/text-console targets: keep VGA/framebuffer consoles, but drop
|
'(;; Keep DRM/KMS enabled so the installer has a local console on generic
|
||||||
;; DRM/KMS GPU drivers and display acceleration stacks.
|
;; virtual and real hardware. This costs roughly 15 MiB in the kexec image
|
||||||
"DRM"
|
;; compared to disabling DRM wholesale, but preserves Proxmox/QEMU VGA and
|
||||||
|
;; common real-hardware GPU/BMC consoles.
|
||||||
|
|
||||||
;; No audio output/input stack on Tribes server deployments.
|
;; No audio output/input stack on Tribes server deployments.
|
||||||
"SOUND"
|
"SOUND"
|
||||||
|
|||||||
+17
-18
@@ -8,12 +8,11 @@
|
|||||||
#:use-module (gnu packages bash)
|
#:use-module (gnu packages bash)
|
||||||
#:use-module (gnu packages base)
|
#:use-module (gnu packages base)
|
||||||
#:use-module (gnu packages compression)
|
#:use-module (gnu packages compression)
|
||||||
#:use-module (gnu packages elixir)
|
|
||||||
#:use-module (gnu packages erlang)
|
|
||||||
#:use-module (gnu packages node)
|
#:use-module (gnu packages node)
|
||||||
#:use-module (gnu packages certs)
|
#:use-module (gnu packages certs)
|
||||||
#:use-module (gnu packages nss)
|
#:use-module (gnu packages nss)
|
||||||
#:use-module (gnu packages version-control)
|
#:use-module (gnu packages version-control)
|
||||||
|
#:use-module (tribes packages otp)
|
||||||
#:export (fetch-mix-deps
|
#:export (fetch-mix-deps
|
||||||
fetch-npm-deps
|
fetch-npm-deps
|
||||||
mix-release-package))
|
mix-release-package))
|
||||||
@@ -44,14 +43,14 @@ SOURCE according to mix.lock."
|
|||||||
(string-append work "/ca-certificates.crt"))
|
(string-append work "/ca-certificates.crt"))
|
||||||
(define hex-lib-dir
|
(define hex-lib-dir
|
||||||
(string-append
|
(string-append
|
||||||
#$(file-append elixir-hex "/lib/elixir/1.19")
|
#$(file-append elixir-hex-otp28 "/lib/elixir/1.19")
|
||||||
":"
|
":"
|
||||||
#$(file-append elixir-hex "/lib/elixir/1.18")))
|
#$(file-append elixir-hex-otp28 "/lib/elixir/1.18")))
|
||||||
(define path
|
(define path
|
||||||
(string-join
|
(string-join
|
||||||
(list #$(file-append elixir "/bin")
|
(list #$(file-append elixir-otp28 "/bin")
|
||||||
#$(file-append elixir-hex "/bin")
|
#$(file-append elixir-hex-otp28 "/bin")
|
||||||
#$(file-append rebar3 "/bin")
|
#$(file-append rebar3-otp28 "/bin")
|
||||||
#$(file-append bash-minimal "/bin")
|
#$(file-append bash-minimal "/bin")
|
||||||
#$(file-append coreutils "/bin")
|
#$(file-append coreutils "/bin")
|
||||||
#$(file-append findutils "/bin")
|
#$(file-append findutils "/bin")
|
||||||
@@ -82,7 +81,7 @@ SOURCE according to mix.lock."
|
|||||||
(setenv "MIX_ENV" #$mix-env)
|
(setenv "MIX_ENV" #$mix-env)
|
||||||
(setenv "MIX_TARGET" #$mix-target)
|
(setenv "MIX_TARGET" #$mix-target)
|
||||||
(setenv "MIX_OS_CONCURRENCY_LOCK" "0")
|
(setenv "MIX_OS_CONCURRENCY_LOCK" "0")
|
||||||
(setenv "MIX_REBAR3" #$(file-append rebar3 "/bin/rebar3"))
|
(setenv "MIX_REBAR3" #$(file-append rebar3-otp28 "/bin/rebar3"))
|
||||||
(setenv "REBAR_GLOBAL_CONFIG_DIR" (string-append work "/rebar3"))
|
(setenv "REBAR_GLOBAL_CONFIG_DIR" (string-append work "/rebar3"))
|
||||||
(setenv "REBAR_CACHE_DIR" (string-append work "/rebar3.cache"))
|
(setenv "REBAR_CACHE_DIR" (string-append work "/rebar3.cache"))
|
||||||
(setenv "LANG" "C.UTF-8")
|
(setenv "LANG" "C.UTF-8")
|
||||||
@@ -280,16 +279,16 @@ MIX-FOD-DEPS as a pre-fetched dependency tree."
|
|||||||
(string-append work "/ca-certificates.crt"))
|
(string-append work "/ca-certificates.crt"))
|
||||||
(define hex-lib-dir
|
(define hex-lib-dir
|
||||||
(string-append
|
(string-append
|
||||||
#$(file-append elixir-hex "/lib/elixir/1.19")
|
#$(file-append elixir-hex-otp28 "/lib/elixir/1.19")
|
||||||
":"
|
":"
|
||||||
#$(file-append elixir-hex "/lib/elixir/1.18")))
|
#$(file-append elixir-hex-otp28 "/lib/elixir/1.18")))
|
||||||
(define aclocal-path
|
(define aclocal-path
|
||||||
(string-join (list #$@aclocal-dirs) ":"))
|
(string-join (list #$@aclocal-dirs) ":"))
|
||||||
(define path
|
(define path
|
||||||
(string-join
|
(string-join
|
||||||
(list #$(file-append elixir "/bin")
|
(list #$(file-append elixir-otp28 "/bin")
|
||||||
#$(file-append elixir-hex "/bin")
|
#$(file-append elixir-hex-otp28 "/bin")
|
||||||
#$(file-append rebar3 "/bin")
|
#$(file-append rebar3-otp28 "/bin")
|
||||||
#$(file-append bash-minimal "/bin")
|
#$(file-append bash-minimal "/bin")
|
||||||
#$(file-append coreutils "/bin")
|
#$(file-append coreutils "/bin")
|
||||||
#$(file-append findutils "/bin")
|
#$(file-append findutils "/bin")
|
||||||
@@ -330,8 +329,8 @@ MIX-FOD-DEPS as a pre-fetched dependency tree."
|
|||||||
(setenv "MIX_OS_CONCURRENCY_LOCK" "0")
|
(setenv "MIX_OS_CONCURRENCY_LOCK" "0")
|
||||||
(setenv "MIX_OS_DEPS_COMPILE_PARTITION_COUNT" "6")
|
(setenv "MIX_OS_DEPS_COMPILE_PARTITION_COUNT" "6")
|
||||||
(setenv "HEX_OFFLINE" "1")
|
(setenv "HEX_OFFLINE" "1")
|
||||||
(setenv "MIX_REBAR" #$(file-append rebar3 "/bin/rebar3"))
|
(setenv "MIX_REBAR" #$(file-append rebar3-otp28 "/bin/rebar3"))
|
||||||
(setenv "MIX_REBAR3" #$(file-append rebar3 "/bin/rebar3"))
|
(setenv "MIX_REBAR3" #$(file-append rebar3-otp28 "/bin/rebar3"))
|
||||||
(setenv "REBAR_GLOBAL_CONFIG_DIR" (string-append work "/rebar3"))
|
(setenv "REBAR_GLOBAL_CONFIG_DIR" (string-append work "/rebar3"))
|
||||||
(setenv "REBAR_CACHE_DIR" (string-append work "/rebar3.cache"))
|
(setenv "REBAR_CACHE_DIR" (string-append work "/rebar3.cache"))
|
||||||
(setenv "SHELL" #$(file-append bash-minimal "/bin/sh"))
|
(setenv "SHELL" #$(file-append bash-minimal "/bin/sh"))
|
||||||
@@ -386,9 +385,9 @@ MIX-FOD-DEPS as a pre-fetched dependency tree."
|
|||||||
findutils
|
findutils
|
||||||
git-minimal
|
git-minimal
|
||||||
nss-certs
|
nss-certs
|
||||||
rebar3
|
rebar3-otp28
|
||||||
elixir
|
elixir-otp28
|
||||||
elixir-hex)
|
elixir-hex-otp28)
|
||||||
native-inputs))
|
native-inputs))
|
||||||
(inputs inputs)
|
(inputs inputs)
|
||||||
(arguments package-arguments)
|
(arguments package-arguments)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
(define-module (tribes packages otp)
|
||||||
|
#:use-module (guix base32)
|
||||||
|
#: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 elixir)
|
||||||
|
#:use-module (gnu packages erlang)
|
||||||
|
#:use-module (gnu packages perl)
|
||||||
|
#:export (erlang-28
|
||||||
|
rebar3-otp28
|
||||||
|
elixir-otp28
|
||||||
|
elixir-hex-otp28))
|
||||||
|
|
||||||
|
(define-public erlang-28
|
||||||
|
(package
|
||||||
|
(inherit erlang)
|
||||||
|
(name "erlang-28")
|
||||||
|
(version "28.5.0.2")
|
||||||
|
(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
|
||||||
|
"0far6szk9h85njn7vwpg4pp9zkxrbyak0w7cr8iymg90s693c34q"))
|
||||||
|
(patches (search-patches "erlang-man-path.patch"))))
|
||||||
|
(arguments
|
||||||
|
(substitute-keyword-arguments (package-arguments erlang)
|
||||||
|
((#:configure-flags flags)
|
||||||
|
`(append
|
||||||
|
(map (lambda (flag)
|
||||||
|
(if (string=? flag "--enable-wx")
|
||||||
|
"--without-wx"
|
||||||
|
flag))
|
||||||
|
,flags)
|
||||||
|
;; OTP does not automatically skip applications that depend on wx.
|
||||||
|
'("--without-debugger"
|
||||||
|
"--without-observer"
|
||||||
|
"--without-et"
|
||||||
|
"--without-reltool")))
|
||||||
|
((#:phases phases)
|
||||||
|
`(modify-phases ,phases
|
||||||
|
;; OTP 28.5.0.2 no longer creates this directory during the first
|
||||||
|
;; pass, but the inherited second-pass clean target still rmdirs it.
|
||||||
|
(add-after 'copy-modified-compiler
|
||||||
|
'create-erl-interface-erts-clean-dir
|
||||||
|
(lambda _
|
||||||
|
(mkdir-p "lib/erl_interface/src/erts")))))))
|
||||||
|
(inputs
|
||||||
|
(modify-inputs (package-inputs erlang)
|
||||||
|
(delete "wxwidgets")))
|
||||||
|
(propagated-inputs '())
|
||||||
|
(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
|
||||||
|
"02k1dvjfqq4pml8p789spkpj99szsiqqbzhd8kmb9dx30g565mzy"))))))))
|
||||||
|
|
||||||
|
(define-public rebar3-otp28
|
||||||
|
(package
|
||||||
|
(inherit rebar3)
|
||||||
|
(name "rebar3-otp28")
|
||||||
|
(native-inputs
|
||||||
|
(modify-inputs (package-native-inputs rebar3)
|
||||||
|
(replace "erlang" erlang-28)))))
|
||||||
|
|
||||||
|
(define-public elixir-otp28
|
||||||
|
(package
|
||||||
|
(inherit elixir)
|
||||||
|
(name "elixir-otp28")
|
||||||
|
(arguments
|
||||||
|
(substitute-keyword-arguments (package-arguments elixir)
|
||||||
|
((#:tests? _ #f)
|
||||||
|
#f)))
|
||||||
|
(inputs
|
||||||
|
(modify-inputs (package-inputs elixir)
|
||||||
|
(replace "erlang" erlang-28)
|
||||||
|
(replace "rebar3" rebar3-otp28)))))
|
||||||
|
|
||||||
|
(define-public elixir-hex-otp28
|
||||||
|
(package
|
||||||
|
(inherit elixir-hex)
|
||||||
|
(name "elixir-hex-otp28")
|
||||||
|
(inputs
|
||||||
|
(modify-inputs (package-inputs elixir-hex)
|
||||||
|
(replace "elixir" elixir-otp28)))))
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"https://git.teralink.net/tribes/tribes.git")
|
"https://git.teralink.net/tribes/tribes.git")
|
||||||
|
|
||||||
(define %tribes-commit
|
(define %tribes-commit
|
||||||
"408c39553e4258dd75409eebfa0ffa4380591be0")
|
"b114d73de8e11e10197c02fd53cdb39e2ab5d33a")
|
||||||
|
|
||||||
(define %tribes-revision "1")
|
(define %tribes-revision "1")
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
(git-version "0.2.0" %tribes-revision %tribes-commit))
|
(git-version "0.2.0" %tribes-revision %tribes-commit))
|
||||||
|
|
||||||
(define %tribes-source-sha256
|
(define %tribes-source-sha256
|
||||||
"16xn3vs6py74z4wrclwapzh18frrp5i663clvwid4l4kmivz833y")
|
"0sbsn7d1lqfl60jpb0afqacc638z07j3zwdw3msmadh6lr06bk5i")
|
||||||
|
|
||||||
(define %tribes-upstream-source
|
(define %tribes-upstream-source
|
||||||
(origin
|
(origin
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ QUIC support.")
|
|||||||
#:make-flags
|
#:make-flags
|
||||||
#~(list "LUA_LIB_NAME=lua"
|
#~(list "LUA_LIB_NAME=lua"
|
||||||
"TARGET=linux-glibc"
|
"TARGET=linux-glibc"
|
||||||
|
"USE_LINUX_CAP=1"
|
||||||
"USE_LUA=1"
|
"USE_LUA=1"
|
||||||
"USE_OPENSSL_AWSLC=1"
|
"USE_OPENSSL_AWSLC=1"
|
||||||
"USE_PCRE2=1"
|
"USE_PCRE2=1"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
%aether-home-page)
|
%aether-home-page)
|
||||||
|
|
||||||
(define %aether-commit
|
(define %aether-commit
|
||||||
"80101b7e78808cea9151f1827777edea5c08ba1f")
|
"995160f95e31efe4d026662885d4b016f144ce9a")
|
||||||
|
|
||||||
(define %aether-revision "1")
|
(define %aether-revision "1")
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
(git-version "0.2.0" %aether-revision %aether-commit))
|
(git-version "0.2.0" %aether-revision %aether-commit))
|
||||||
|
|
||||||
(define %aether-source-sha256
|
(define %aether-source-sha256
|
||||||
"0shylw4s75djanqm7h82j8advjg96im6n4wr6fz6kwbj5hs8aq4b")
|
"1jp52q70z1djiglm03b81zh7zgn87gbf207xwih24h6a0zddsmgs")
|
||||||
|
|
||||||
(define %aether-mix-deps-sha256
|
(define %aether-mix-deps-sha256
|
||||||
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"External Tribes plugin artifact for Aether, packaged as a Guix-managed
|
"External Tribes plugin artifact for Aether, packaged as a Guix-managed
|
||||||
plugin directory."
|
plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.aether"
|
#:plugin-id "org.tribe-one.plugins.aether"
|
||||||
#:plugin-slug "aether"
|
#:plugin-slug "tribe-one-aether"
|
||||||
#:display-name "Aether"
|
#:display-name "Aether"
|
||||||
#:provides '("org.tribe-one.caps.social@1" "org.tribe-one.caps.chat@1")
|
#:provides '("org.tribe-one.caps.social@1" "org.tribe-one.caps.chat@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
@@ -104,7 +104,7 @@ artifact."
|
|||||||
"External Tribes plugin artifact for Aether, packaged as a Guix-managed
|
"External Tribes plugin artifact for Aether, packaged as a Guix-managed
|
||||||
plugin directory."
|
plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.aether"
|
#:plugin-id "org.tribe-one.plugins.aether"
|
||||||
#:plugin-slug "aether"
|
#:plugin-slug "tribe-one-aether"
|
||||||
#:display-name "Aether"
|
#:display-name "Aether"
|
||||||
#:provides '("org.tribe-one.caps.social@1" "org.tribe-one.caps.chat@1")
|
#:provides '("org.tribe-one.caps.social@1" "org.tribe-one.caps.chat@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
(define guix-tribes-built-in-plugin-definitions
|
(define guix-tribes-built-in-plugin-definitions
|
||||||
(list
|
(list
|
||||||
(tribes-plugin-definition
|
(tribes-plugin-definition
|
||||||
(name "tribes_ui")
|
(name "tribe-one-tribes-ui")
|
||||||
(package-name "tribes")
|
(package-name "tribes")
|
||||||
(version "0.1.0")
|
(version "0.1.0")
|
||||||
(synopsis "Default Tribes UI capability provider")
|
(synopsis "Default Tribes UI capability provider")
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
%kobold-home-page)
|
%kobold-home-page)
|
||||||
|
|
||||||
(define %kobold-commit
|
(define %kobold-commit
|
||||||
"74b6c44e4dcfbeaf02f77620b5675f11781ad1eb")
|
"4658b762411f014b531d4acc5aaea05463dbfca3")
|
||||||
|
|
||||||
(define %kobold-revision "1")
|
(define %kobold-revision "1")
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
(git-version "0.1.0" %kobold-revision %kobold-commit))
|
(git-version "0.1.0" %kobold-revision %kobold-commit))
|
||||||
|
|
||||||
(define %kobold-source-sha256
|
(define %kobold-source-sha256
|
||||||
"1xxysbslh1fa57873n4669mi874byv861w934mz9g3zszr120ijn")
|
"0qrssm32apandr2m4fsh56v6ay7b31630k7g033f17fwxlrlbq34")
|
||||||
|
|
||||||
(define %kobold-mix-deps-sha256
|
(define %kobold-mix-deps-sha256
|
||||||
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"External Tribes plugin artifact for Kobold distributed datasets,
|
"External Tribes plugin artifact for Kobold distributed datasets,
|
||||||
packaged as a Guix-managed plugin directory."
|
packaged as a Guix-managed plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.kobold"
|
#:plugin-id "org.tribe-one.plugins.kobold"
|
||||||
#:plugin-slug "kobold"
|
#:plugin-slug "tribe-one-kobold"
|
||||||
#:display-name "Kobold"
|
#:display-name "Kobold"
|
||||||
#:provides '("org.tribes.kobold.dataset@1")
|
#:provides '("org.tribes.kobold.dataset@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1" "org.tribes.alliance.trust@1")
|
#:requires '("org.tribe-one.caps.ui@1" "org.tribes.alliance.trust@1")
|
||||||
@@ -103,7 +103,7 @@ packaged as a Guix-managed plugin directory."
|
|||||||
"External Tribes plugin artifact for Kobold distributed datasets,
|
"External Tribes plugin artifact for Kobold distributed datasets,
|
||||||
packaged as a Guix-managed plugin directory."
|
packaged as a Guix-managed plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.kobold"
|
#:plugin-id "org.tribe-one.plugins.kobold"
|
||||||
#:plugin-slug "kobold"
|
#:plugin-slug "tribe-one-kobold"
|
||||||
#:display-name "Kobold"
|
#:display-name "Kobold"
|
||||||
#:provides '("org.tribes.kobold.dataset@1")
|
#:provides '("org.tribes.kobold.dataset@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1" "org.tribes.alliance.trust@1")
|
#:requires '("org.tribe-one.caps.ui@1" "org.tribes.alliance.trust@1")
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
%sender-home-page)
|
%sender-home-page)
|
||||||
|
|
||||||
(define %sender-commit
|
(define %sender-commit
|
||||||
"ee7d0ac29fb583e1c5f75001984622c2ba7e56b1")
|
"cdbfef7cd300c581b74b7aa61e7c35fb52e7ccff")
|
||||||
|
|
||||||
(define %sender-revision "1")
|
(define %sender-revision "1")
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
(git-version "0.1.0" %sender-revision %sender-commit))
|
(git-version "0.1.0" %sender-revision %sender-commit))
|
||||||
|
|
||||||
(define %sender-source-sha256
|
(define %sender-source-sha256
|
||||||
"1bbgi20j99ym9yiv78w3j590wpf400bdkfiqf9s1ra31dgfzzq4v")
|
"1nbybxiyihqv0avjkrl4x1k0iz5cyljcs38zvb6kln474v6qz0ly")
|
||||||
|
|
||||||
(define %sender-mix-deps-sha256
|
(define %sender-mix-deps-sha256
|
||||||
"08mdy38247dqni8f84y09m8vz6hvjakvc4ml28x1jxqvq53s4nq3")
|
"08mdy38247dqni8f84y09m8vz6hvjakvc4ml28x1jxqvq53s4nq3")
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"External Tribes plugin artifact for RTMP ingest and HLS streaming,
|
"External Tribes plugin artifact for RTMP ingest and HLS streaming,
|
||||||
packaged as a Guix-managed plugin directory."
|
packaged as a Guix-managed plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.sender"
|
#:plugin-id "org.tribe-one.plugins.sender"
|
||||||
#:plugin-slug "sender"
|
#:plugin-slug "tribe-one-sender"
|
||||||
#:display-name "Sender"
|
#:display-name "Sender"
|
||||||
#:provides '("org.tribe-one.caps.sender@1")
|
#:provides '("org.tribe-one.caps.sender@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
@@ -112,7 +112,7 @@ artifact."
|
|||||||
"External Tribes plugin artifact for RTMP ingest and HLS streaming,
|
"External Tribes plugin artifact for RTMP ingest and HLS streaming,
|
||||||
packaged as a Guix-managed plugin directory."
|
packaged as a Guix-managed plugin directory."
|
||||||
#:plugin-id "org.tribe-one.plugins.sender"
|
#:plugin-id "org.tribe-one.plugins.sender"
|
||||||
#:plugin-slug "sender"
|
#:plugin-slug "tribe-one-sender"
|
||||||
#:display-name "Sender"
|
#:display-name "Sender"
|
||||||
#:provides '("org.tribe-one.caps.sender@1")
|
#:provides '("org.tribe-one.caps.sender@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
%supertest-home-page)
|
%supertest-home-page)
|
||||||
|
|
||||||
(define %supertest-commit
|
(define %supertest-commit
|
||||||
"afc38412c4362ea2e5b1fe9fe08f1cffe60edf34")
|
"029ba23b751c44d4cd9460ea61a47b36b53276f3")
|
||||||
|
|
||||||
(define %supertest-revision "1")
|
(define %supertest-revision "1")
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
(git-version "0.1.1" %supertest-revision %supertest-commit))
|
(git-version "0.1.1" %supertest-revision %supertest-commit))
|
||||||
|
|
||||||
(define %supertest-source-sha256
|
(define %supertest-source-sha256
|
||||||
"1si0bis5k47j22cv7cbbah86ilrxvrbncld4isvyb17zan7ig0q6")
|
"1l7kw7sv92dfsf6m1zzgc4gbpfqyx98c613fc3xic7gwsxyzznfp")
|
||||||
|
|
||||||
(define %supertest-mix-deps-sha256
|
(define %supertest-mix-deps-sha256
|
||||||
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
#:description
|
#:description
|
||||||
"External Tribes plugin artifact used by live rollout and sync tests."
|
"External Tribes plugin artifact used by live rollout and sync tests."
|
||||||
#:plugin-id "org.tribe-one.plugins.supertest"
|
#:plugin-id "org.tribe-one.plugins.supertest"
|
||||||
#:plugin-slug "supertest"
|
#:plugin-slug "tribe-one-supertest"
|
||||||
#:display-name "Supertest"
|
#:display-name "Supertest"
|
||||||
#:provides '()
|
#:provides '()
|
||||||
#:requires '()
|
#:requires '()
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
#:description
|
#:description
|
||||||
"External Tribes plugin artifact used by live rollout and sync tests."
|
"External Tribes plugin artifact used by live rollout and sync tests."
|
||||||
#:plugin-id "org.tribe-one.plugins.supertest"
|
#:plugin-id "org.tribe-one.plugins.supertest"
|
||||||
#:plugin-slug "supertest"
|
#:plugin-slug "tribe-one-supertest"
|
||||||
#:display-name "Supertest"
|
#:display-name "Supertest"
|
||||||
#:provides '()
|
#:provides '()
|
||||||
#:requires '()
|
#:requires '()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
%trust-home-page)
|
%trust-home-page)
|
||||||
|
|
||||||
(define %trust-commit
|
(define %trust-commit
|
||||||
"f08af20cd5cd2dbbb50e4472bf1a5d8ed1b73c21")
|
"157106aa66ecd7ce5f7f5a8a90c30a1f22e2fe74")
|
||||||
|
|
||||||
(define %trust-revision "1")
|
(define %trust-revision "1")
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
(git-version "0.1.0" %trust-revision %trust-commit))
|
(git-version "0.1.0" %trust-revision %trust-commit))
|
||||||
|
|
||||||
(define %trust-source-sha256
|
(define %trust-source-sha256
|
||||||
"1zsg57mr3bjxrxvim77z2as1jqr8a3anfp0jgqz0ycz6rzai58dp")
|
"0k1gzpd5f5q3mczmxw0rwx7zwqxkspzk0zfpm1a130fd4dqc9y5z")
|
||||||
|
|
||||||
(define %trust-mix-deps-sha256
|
(define %trust-mix-deps-sha256
|
||||||
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
"1pk1qv8skbgzi0wg59zj9aiyxx2hxl2k6ngxqqbwvj7wsbiz95bb")
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
#:description
|
#:description
|
||||||
"External Tribes plugin artifact for tribe-to-tribe trust, alliance, and federation provider behavior."
|
"External Tribes plugin artifact for tribe-to-tribe trust, alliance, and federation provider behavior."
|
||||||
#:plugin-id "org.tribe-one.plugins.trust"
|
#:plugin-id "org.tribe-one.plugins.trust"
|
||||||
#:plugin-slug "trust"
|
#:plugin-slug "tribe-one-trust"
|
||||||
#:display-name "Trust"
|
#:display-name "Trust"
|
||||||
#:provides '("org.tribes.alliance.trust@1" "org.tribes.federation.provider@1" "org.tribes.access.trust_provider@1")
|
#:provides '("org.tribes.alliance.trust@1" "org.tribes.federation.provider@1" "org.tribes.access.trust_provider@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
#:description
|
#:description
|
||||||
"External Tribes plugin artifact for tribe-to-tribe trust, alliance, and federation provider behavior."
|
"External Tribes plugin artifact for tribe-to-tribe trust, alliance, and federation provider behavior."
|
||||||
#:plugin-id "org.tribe-one.plugins.trust"
|
#:plugin-id "org.tribe-one.plugins.trust"
|
||||||
#:plugin-slug "trust"
|
#:plugin-slug "tribe-one-trust"
|
||||||
#:display-name "Trust"
|
#:display-name "Trust"
|
||||||
#:provides '("org.tribes.alliance.trust@1" "org.tribes.federation.provider@1" "org.tribes.access.trust_provider@1")
|
#:provides '("org.tribes.alliance.trust@1" "org.tribes.federation.provider@1" "org.tribes.access.trust_provider@1")
|
||||||
#:requires '("org.tribe-one.caps.ui@1")
|
#:requires '("org.tribe-one.caps.ui@1")
|
||||||
|
|||||||
+27
-21
@@ -83,6 +83,19 @@
|
|||||||
(define (haproxy-lines lines)
|
(define (haproxy-lines lines)
|
||||||
(string-concatenate (map haproxy-indent lines)))
|
(string-concatenate (map haproxy-indent lines)))
|
||||||
|
|
||||||
|
(define (haproxy-crt-arguments pem-files)
|
||||||
|
(string-join
|
||||||
|
(append-map (lambda (pem-file)
|
||||||
|
(list "crt" pem-file))
|
||||||
|
pem-files)
|
||||||
|
" "))
|
||||||
|
|
||||||
|
(define (haproxy-tls-bind-line frontend pem-files alpn)
|
||||||
|
(string-append "bind " frontend
|
||||||
|
" ssl "
|
||||||
|
(haproxy-crt-arguments pem-files)
|
||||||
|
" alpn " alpn))
|
||||||
|
|
||||||
(define (haproxy-http-frontend http-frontends acme-backend)
|
(define (haproxy-http-frontend http-frontends acme-backend)
|
||||||
(if (null? http-frontends)
|
(if (null? http-frontends)
|
||||||
""
|
""
|
||||||
@@ -96,14 +109,14 @@
|
|||||||
(if acme-backend
|
(if acme-backend
|
||||||
'("acl acme_challenge path_beg /.well-known/acme-challenge/"
|
'("acl acme_challenge path_beg /.well-known/acme-challenge/"
|
||||||
"http-request redirect scheme https code 308 unless acme_challenge"
|
"http-request redirect scheme https code 308 unless acme_challenge"
|
||||||
"use_backend lego_acme if acme_challenge")
|
"use_backend tribes_acme if acme_challenge")
|
||||||
'("http-request redirect scheme https code 308"))))
|
'("http-request redirect scheme https code 308"))))
|
||||||
"\n"
|
"\n"
|
||||||
(if acme-backend
|
(if acme-backend
|
||||||
(string-append
|
(string-append
|
||||||
"backend lego_acme\n"
|
"backend tribes_acme\n"
|
||||||
(haproxy-lines
|
(haproxy-lines
|
||||||
(list (string-append "server lego " acme-backend)))
|
(list (string-append "server tribes " acme-backend)))
|
||||||
"\n")
|
"\n")
|
||||||
""))))
|
""))))
|
||||||
|
|
||||||
@@ -119,6 +132,7 @@
|
|||||||
(haproxy-lines
|
(haproxy-lines
|
||||||
(append
|
(append
|
||||||
(list "log /dev/log local0"
|
(list "log /dev/log local0"
|
||||||
|
"setcap cap_net_bind_service"
|
||||||
(string-append "user " user)
|
(string-append "user " user)
|
||||||
(string-append "group " group)
|
(string-append "group " group)
|
||||||
"maxconn 32768"
|
"maxconn 32768"
|
||||||
@@ -144,25 +158,17 @@
|
|||||||
"frontend tribes_tls\n"
|
"frontend tribes_tls\n"
|
||||||
(haproxy-lines
|
(haproxy-lines
|
||||||
(append
|
(append
|
||||||
(append-map
|
(if (null? pem-files)
|
||||||
(lambda (frontend)
|
'()
|
||||||
(map
|
(append
|
||||||
(lambda (pem-file)
|
(map (lambda (frontend)
|
||||||
(string-append "bind " frontend
|
(haproxy-tls-bind-line frontend pem-files "h2,http/1.1"))
|
||||||
" ssl crt " pem-file
|
frontends)
|
||||||
" alpn h2,http/1.1"))
|
(map (lambda (frontend)
|
||||||
pem-files))
|
(haproxy-tls-bind-line frontend pem-files "h3"))
|
||||||
frontends)
|
quic-frontends)))
|
||||||
(append-map
|
|
||||||
(lambda (frontend)
|
|
||||||
(map
|
|
||||||
(lambda (pem-file)
|
|
||||||
(string-append "bind " frontend
|
|
||||||
" ssl crt " pem-file
|
|
||||||
" alpn h3"))
|
|
||||||
pem-files))
|
|
||||||
quic-frontends)
|
|
||||||
'("http-response set-header alt-svc 'h3=\":443\"; ma=86400'")
|
'("http-response set-header alt-svc 'h3=\":443\"; ma=86400'")
|
||||||
|
'("http-response set-header strict-transport-security \"max-age=31536000\"")
|
||||||
'("default_backend tribes_edge_cache")
|
'("default_backend tribes_edge_cache")
|
||||||
extra-frontend))
|
extra-frontend))
|
||||||
"\n"
|
"\n"
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
lego-certificate-configuration-profile
|
lego-certificate-configuration-profile
|
||||||
lego-certificate-configuration-listen-http
|
lego-certificate-configuration-listen-http
|
||||||
lego-certificate-configuration-webroot
|
lego-certificate-configuration-webroot
|
||||||
|
lego-certificate-configuration-dns-provider
|
||||||
|
lego-certificate-configuration-environment-variables
|
||||||
lego-certificate-configuration-key-type
|
lego-certificate-configuration-key-type
|
||||||
lego-certificate-configuration-acme-enabled?
|
lego-certificate-configuration-acme-enabled?
|
||||||
lego-certificate-configuration-renew-days
|
lego-certificate-configuration-renew-days
|
||||||
@@ -29,6 +31,7 @@
|
|||||||
lego-certificate-configuration-reload-services
|
lego-certificate-configuration-reload-services
|
||||||
lego-certificate-directory
|
lego-certificate-directory
|
||||||
lego-certificate-full-pem
|
lego-certificate-full-pem
|
||||||
|
subject-is-ip?
|
||||||
lego-configuration
|
lego-configuration
|
||||||
lego-configuration?
|
lego-configuration?
|
||||||
lego-configuration-package
|
lego-configuration-package
|
||||||
@@ -52,6 +55,10 @@
|
|||||||
(default #f))
|
(default #f))
|
||||||
(webroot lego-certificate-configuration-webroot
|
(webroot lego-certificate-configuration-webroot
|
||||||
(default #f))
|
(default #f))
|
||||||
|
(dns-provider lego-certificate-configuration-dns-provider
|
||||||
|
(default #f))
|
||||||
|
(environment-variables lego-certificate-configuration-environment-variables
|
||||||
|
(default '()))
|
||||||
(key-type lego-certificate-configuration-key-type
|
(key-type lego-certificate-configuration-key-type
|
||||||
(default "ec384"))
|
(default "ec384"))
|
||||||
(acme-enabled? lego-certificate-configuration-acme-enabled?
|
(acme-enabled? lego-certificate-configuration-acme-enabled?
|
||||||
@@ -106,6 +113,7 @@
|
|||||||
(define (lego-common-arguments certificate)
|
(define (lego-common-arguments certificate)
|
||||||
(let ((listen-http (lego-certificate-configuration-listen-http certificate))
|
(let ((listen-http (lego-certificate-configuration-listen-http certificate))
|
||||||
(webroot (lego-certificate-configuration-webroot certificate))
|
(webroot (lego-certificate-configuration-webroot certificate))
|
||||||
|
(dns-provider (lego-certificate-configuration-dns-provider certificate))
|
||||||
(subjects (lego-certificate-configuration-subjects certificate))
|
(subjects (lego-certificate-configuration-subjects certificate))
|
||||||
(email (lego-certificate-configuration-email certificate))
|
(email (lego-certificate-configuration-email certificate))
|
||||||
(server (lego-certificate-configuration-server certificate))
|
(server (lego-certificate-configuration-server certificate))
|
||||||
@@ -121,11 +129,17 @@
|
|||||||
(error "lego certificate cannot use both listen-http and webroot"
|
(error "lego certificate cannot use both listen-http and webroot"
|
||||||
(lego-certificate-configuration-name certificate))
|
(lego-certificate-configuration-name certificate))
|
||||||
'())
|
'())
|
||||||
|
(if (and dns-provider (or listen-http webroot))
|
||||||
|
(error "lego certificate cannot combine HTTP and DNS challenge modes"
|
||||||
|
(lego-certificate-configuration-name certificate))
|
||||||
|
'())
|
||||||
(cond
|
(cond
|
||||||
(listen-http
|
(listen-http
|
||||||
(list "--http" "--http.port" listen-http))
|
(list "--http" "--http.port" listen-http))
|
||||||
(webroot
|
(webroot
|
||||||
(list "--http" "--http.webroot" webroot))
|
(list "--http" "--http.webroot" webroot))
|
||||||
|
(dns-provider
|
||||||
|
(list "--dns" dns-provider))
|
||||||
(else
|
(else
|
||||||
(list "--http")))
|
(list "--http")))
|
||||||
(if server
|
(if server
|
||||||
@@ -196,6 +210,8 @@
|
|||||||
(key-output (string-append state-dir "/key.pem"))
|
(key-output (string-append state-dir "/key.pem"))
|
||||||
(full-pem (string-append state-dir "/full.pem"))
|
(full-pem (string-append state-dir "/full.pem"))
|
||||||
(last-run-log (lego-certificate-last-run-log certificate))
|
(last-run-log (lego-certificate-last-run-log certificate))
|
||||||
|
(environment-variables
|
||||||
|
(lego-certificate-configuration-environment-variables certificate))
|
||||||
(run-arguments
|
(run-arguments
|
||||||
(append (lego-common-arguments certificate)
|
(append (lego-common-arguments certificate)
|
||||||
(list "run")
|
(list "run")
|
||||||
@@ -238,6 +254,15 @@
|
|||||||
(new (file-contents #$certificate-file)))
|
(new (file-contents #$certificate-file)))
|
||||||
(not (equal? old new))))
|
(not (equal? old new))))
|
||||||
|
|
||||||
|
(define (apply-environment! variables)
|
||||||
|
(for-each
|
||||||
|
(lambda (variable)
|
||||||
|
(let ((separator (string-index variable #\=)))
|
||||||
|
(when separator
|
||||||
|
(setenv (substring variable 0 separator)
|
||||||
|
(substring variable (+ separator 1))))))
|
||||||
|
variables))
|
||||||
|
|
||||||
(define (run-lego lego args)
|
(define (run-lego lego args)
|
||||||
(let* ((log-port (open-output-file #$last-run-log))
|
(let* ((log-port (open-output-file #$last-run-log))
|
||||||
(port (apply open-pipe* OPEN_READ
|
(port (apply open-pipe* OPEN_READ
|
||||||
@@ -264,6 +289,7 @@
|
|||||||
(run-lego lego args))))
|
(run-lego lego args))))
|
||||||
|
|
||||||
(mkdir-p #$state-dir)
|
(mkdir-p #$state-dir)
|
||||||
|
(apply-environment! '#$environment-variables)
|
||||||
|
|
||||||
(let ((lego #$(file-append
|
(let ((lego #$(file-append
|
||||||
(lego-configuration-package config)
|
(lego-configuration-package config)
|
||||||
|
|||||||
@@ -286,7 +286,7 @@
|
|||||||
#~(setenv "PHX_SERVER" "true")
|
#~(setenv "PHX_SERVER" "true")
|
||||||
#~(setenv "PORT" #$(number->string
|
#~(setenv "PORT" #$(number->string
|
||||||
(tribes-configuration-listen-port config)))
|
(tribes-configuration-listen-port config)))
|
||||||
#~(setenv "PHX_HOST" #$(tribes-configuration-host config))
|
#~(setenv "TRIBES_HOST_CONFIG_FILE" "/etc/tribes/host-config.json")
|
||||||
#~(setenv "DATABASE_URL"
|
#~(setenv "DATABASE_URL"
|
||||||
#$(tribes-database-url
|
#$(tribes-database-url
|
||||||
config
|
config
|
||||||
@@ -295,10 +295,8 @@
|
|||||||
#$(tribes-database-url
|
#$(tribes-database-url
|
||||||
config
|
config
|
||||||
(tribes-configuration-parrhesia-database-name config)))
|
(tribes-configuration-parrhesia-database-name config)))
|
||||||
#~(setenv "PARRHESIA_RELAY_URL" #$(tribes-relay-url config))
|
|
||||||
#~(setenv "PARRHESIA_POOL_SIZE" "30")
|
#~(setenv "PARRHESIA_POOL_SIZE" "30")
|
||||||
#~(setenv "PARRHESIA_READ_POOL_SIZE" "30")
|
#~(setenv "PARRHESIA_READ_POOL_SIZE" "30")
|
||||||
#~(setenv "TRIBES_SYNC_HOST" #$(tribes-sync-host config))
|
|
||||||
#~(setenv "TRIBES_SYNC_PORT"
|
#~(setenv "TRIBES_SYNC_PORT"
|
||||||
#$(number->string
|
#$(number->string
|
||||||
(tribes-configuration-sync-port config)))
|
(tribes-configuration-sync-port config)))
|
||||||
@@ -450,6 +448,7 @@
|
|||||||
(list plugin-dir)
|
(list plugin-dir)
|
||||||
'()))))
|
'()))))
|
||||||
(deploy-dir #$(tribes-deploy-directory config))
|
(deploy-dir #$(tribes-deploy-directory config))
|
||||||
|
(host-config-file "/etc/tribes/host-config.json")
|
||||||
(generated-config-file #$(tribes-generated-configuration-file config))
|
(generated-config-file #$(tribes-generated-configuration-file config))
|
||||||
(human-friendly-config-file
|
(human-friendly-config-file
|
||||||
#$(tribes-human-friendly-configuration-file config))
|
#$(tribes-human-friendly-configuration-file config))
|
||||||
@@ -465,6 +464,9 @@
|
|||||||
(mkdir-p deploy-dir)
|
(mkdir-p deploy-dir)
|
||||||
(chown deploy-dir 0 0)
|
(chown deploy-dir 0 0)
|
||||||
(chmod deploy-dir #o700)
|
(chmod deploy-dir #o700)
|
||||||
|
(when (file-exists? host-config-file)
|
||||||
|
(chown host-config-file 0 gid)
|
||||||
|
(chmod host-config-file #o640))
|
||||||
(mkdir-p (dirname generated-config-file))
|
(mkdir-p (dirname generated-config-file))
|
||||||
(call-with-output-file generated-config-file
|
(call-with-output-file generated-config-file
|
||||||
(lambda (port)
|
(lambda (port)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Tribes service using an explicit host configuration record."
|
|||||||
(let* ((node-config
|
(let* ((node-config
|
||||||
(tribes-node-configuration
|
(tribes-node-configuration
|
||||||
(postgresql (postgresql-configuration
|
(postgresql (postgresql-configuration
|
||||||
(postgresql postgresql)))
|
(postgresql postgresql-17)))
|
||||||
(tribes (tribes-host-configuration-tribes host-configuration))
|
(tribes (tribes-host-configuration-tribes host-configuration))
|
||||||
(edge (tribes-host-configuration-edge host-configuration))
|
(edge (tribes-host-configuration-edge host-configuration))
|
||||||
(enable-bbr? enable-bbr?))))
|
(enable-bbr? enable-bbr?))))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#:use-module (gnu packages cryptsetup)
|
#:use-module (gnu packages cryptsetup)
|
||||||
#:use-module (gnu packages curl)
|
#:use-module (gnu packages curl)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services base)
|
||||||
#:use-module (gnu system file-systems)
|
#:use-module (gnu system file-systems)
|
||||||
#:use-module (gnu system mapped-devices)
|
#:use-module (gnu system mapped-devices)
|
||||||
#:use-module (gnu system uuid)
|
#:use-module (gnu system uuid)
|
||||||
@@ -128,6 +129,34 @@
|
|||||||
profile-service-type
|
profile-service-type
|
||||||
(list clevis cryptsetup curl))))
|
(list clevis cryptsetup curl))))
|
||||||
|
|
||||||
|
(define (public-ipv6-networking-services host-configuration system-facts)
|
||||||
|
(let ((ipv6 (tribes-host-configuration-public-ipv6 host-configuration)))
|
||||||
|
(if ipv6
|
||||||
|
(list
|
||||||
|
(service static-networking-service-type
|
||||||
|
(list
|
||||||
|
(static-networking
|
||||||
|
(provision '(tribes-public-ipv6-networking))
|
||||||
|
(requirement '(networking))
|
||||||
|
(addresses
|
||||||
|
(list
|
||||||
|
(network-address
|
||||||
|
(device (tribes-system-facts-interface system-facts))
|
||||||
|
(value
|
||||||
|
(string-append
|
||||||
|
(tribes-public-ipv6-configuration-address ipv6)
|
||||||
|
"/"
|
||||||
|
(number->string
|
||||||
|
(tribes-public-ipv6-configuration-prefix-length ipv6)))))))
|
||||||
|
(routes
|
||||||
|
(list
|
||||||
|
(network-route
|
||||||
|
(destination "default")
|
||||||
|
(gateway (tribes-public-ipv6-configuration-gateway ipv6))
|
||||||
|
(device (tribes-system-facts-interface system-facts))
|
||||||
|
(ipv6? #t))))))))
|
||||||
|
'())))
|
||||||
|
|
||||||
(define (authorized-keys-local-file system-facts)
|
(define (authorized-keys-local-file system-facts)
|
||||||
(let ((authorized-keys-file
|
(let ((authorized-keys-file
|
||||||
(tribes-system-facts-authorized-keys-file system-facts)))
|
(tribes-system-facts-authorized-keys-file system-facts)))
|
||||||
@@ -153,7 +182,11 @@
|
|||||||
#:initrd (initrd-from-system-facts system-facts)
|
#:initrd (initrd-from-system-facts system-facts)
|
||||||
#:interface (tribes-system-facts-interface system-facts)
|
#:interface (tribes-system-facts-interface system-facts)
|
||||||
#:authorized-keys-file (authorized-keys-local-file system-facts)
|
#:authorized-keys-file (authorized-keys-local-file system-facts)
|
||||||
#:extra-services (extra-services-from-system-facts system-facts)
|
#:extra-services (append
|
||||||
|
(extra-services-from-system-facts system-facts)
|
||||||
|
(public-ipv6-networking-services
|
||||||
|
host-configuration
|
||||||
|
system-facts))
|
||||||
#:enable-bbr? (tribes-system-facts-enable-bbr? system-facts)))
|
#:enable-bbr? (tribes-system-facts-enable-bbr? system-facts)))
|
||||||
|
|
||||||
(define* (tribes-operating-system-from-json-files
|
(define* (tribes-operating-system-from-json-files
|
||||||
|
|||||||
+148
-36
@@ -1,7 +1,9 @@
|
|||||||
(define-module (tribes system node)
|
(define-module (tribes system node)
|
||||||
|
#:use-module (gnu packages)
|
||||||
#:use-module (gnu packages databases)
|
#:use-module (gnu packages databases)
|
||||||
#:use-module (gnu packages linux)
|
#:use-module (gnu packages linux)
|
||||||
#:use-module (gnu packages monitoring)
|
#:use-module (gnu packages monitoring)
|
||||||
|
#:use-module (gnu packages tls)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
#:use-module (gnu services databases)
|
#:use-module (gnu services databases)
|
||||||
#:use-module (gnu services linux)
|
#:use-module (gnu services linux)
|
||||||
@@ -14,7 +16,6 @@
|
|||||||
#:use-module (tribes packages plugins)
|
#:use-module (tribes packages plugins)
|
||||||
#:use-module (tribes services chrony)
|
#:use-module (tribes services chrony)
|
||||||
#:use-module (tribes services haproxy)
|
#:use-module (tribes services haproxy)
|
||||||
#:use-module (tribes services lego)
|
|
||||||
#:use-module (tribes services tribes)
|
#:use-module (tribes services tribes)
|
||||||
#:use-module (tribes services vinyl)
|
#:use-module (tribes services vinyl)
|
||||||
#:use-module (tribes services vinyl-exporter)
|
#:use-module (tribes services vinyl-exporter)
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
tribes-edge-configuration?
|
tribes-edge-configuration?
|
||||||
tribes-edge-configuration-certificate-name
|
tribes-edge-configuration-certificate-name
|
||||||
tribes-edge-configuration-certificate-subjects
|
tribes-edge-configuration-certificate-subjects
|
||||||
tribes-edge-configuration-certificate-email
|
|
||||||
tribes-edge-configuration-certificate-profile
|
tribes-edge-configuration-certificate-profile
|
||||||
tribes-edge-configuration-renew-days
|
tribes-edge-configuration-renew-days
|
||||||
tribes-edge-configuration-http-port
|
tribes-edge-configuration-http-port
|
||||||
@@ -48,8 +48,6 @@
|
|||||||
(default "tribes"))
|
(default "tribes"))
|
||||||
(certificate-subjects tribes-edge-configuration-certificate-subjects
|
(certificate-subjects tribes-edge-configuration-certificate-subjects
|
||||||
(default '()))
|
(default '()))
|
||||||
(certificate-email tribes-edge-configuration-certificate-email
|
|
||||||
(default #f))
|
|
||||||
(certificate-profile tribes-edge-configuration-certificate-profile
|
(certificate-profile tribes-edge-configuration-certificate-profile
|
||||||
(default "shortlived"))
|
(default "shortlived"))
|
||||||
(renew-days tribes-edge-configuration-renew-days
|
(renew-days tribes-edge-configuration-renew-days
|
||||||
@@ -74,7 +72,12 @@
|
|||||||
tribes-node-configuration?
|
tribes-node-configuration?
|
||||||
(postgresql tribes-node-configuration-postgresql
|
(postgresql tribes-node-configuration-postgresql
|
||||||
(default (postgresql-configuration
|
(default (postgresql-configuration
|
||||||
(postgresql postgresql))))
|
(postgresql postgresql-17)
|
||||||
|
(config-file
|
||||||
|
(postgresql-config-file
|
||||||
|
(extra-config
|
||||||
|
'(("log_min_duration_statement" 1000)
|
||||||
|
("log_line_prefix" "%m [%p] user=%u db=%d app=%a client=%h "))))))))
|
||||||
(tribes tribes-node-configuration-tribes
|
(tribes tribes-node-configuration-tribes
|
||||||
(default (tribes-configuration)))
|
(default (tribes-configuration)))
|
||||||
(edge tribes-node-configuration-edge
|
(edge tribes-node-configuration-edge
|
||||||
@@ -89,34 +92,109 @@
|
|||||||
(name (tribes-configuration-database-user tribes))
|
(name (tribes-configuration-database-user tribes))
|
||||||
(permissions '(createdb login))))))
|
(permissions '(createdb login))))))
|
||||||
|
|
||||||
(define (edge-certificate-subjects edge tribes)
|
(define (edge-certificate-subjects edge _tribes)
|
||||||
(let ((subjects (tribes-edge-configuration-certificate-subjects edge)))
|
(let ((subjects (tribes-edge-configuration-certificate-subjects edge)))
|
||||||
(if (null? subjects)
|
(if (null? subjects)
|
||||||
(list (tribes-configuration-host tribes))
|
(error "edge certificate requires explicit IP subjects")
|
||||||
subjects)))
|
subjects)))
|
||||||
|
|
||||||
(define (edge-certificate-config edge tribes)
|
(define %edge-acme-state-directory "/var/lib/tribes/acme")
|
||||||
|
(define %edge-acme-key-file
|
||||||
|
(string-append %edge-acme-state-directory "/edge.key"))
|
||||||
|
(define %edge-acme-fullchain-file
|
||||||
|
(string-append %edge-acme-state-directory "/edge.fullchain.pem"))
|
||||||
|
(define %edge-haproxy-pem-file
|
||||||
|
(string-append %edge-acme-state-directory "/edge.full.pem"))
|
||||||
|
|
||||||
|
(define (subject-is-ip? subject)
|
||||||
|
(or (and (false-if-exception (inet-pton AF_INET subject)) #t)
|
||||||
|
(and (false-if-exception (inet-pton AF_INET6 subject)) #t)))
|
||||||
|
|
||||||
|
(define (subject-is-dns? subject)
|
||||||
|
(define (label-char? char)
|
||||||
|
(or (char-alphabetic? char)
|
||||||
|
(char-numeric? char)
|
||||||
|
(char=? char #\-)))
|
||||||
|
(define (label-valid? label)
|
||||||
|
(let ((length (string-length label)))
|
||||||
|
(and (> length 0)
|
||||||
|
(<= length 63)
|
||||||
|
(let ((first (string-ref label 0))
|
||||||
|
(last (string-ref label (- length 1))))
|
||||||
|
(and (or (char-alphabetic? first) (char-numeric? first))
|
||||||
|
(or (char-alphabetic? last) (char-numeric? last))
|
||||||
|
(string-every label-char? label))))))
|
||||||
|
(and (string? subject)
|
||||||
|
(> (string-length subject) 0)
|
||||||
|
(<= (string-length subject) 253)
|
||||||
|
(not (string-prefix? "." subject))
|
||||||
|
(not (string-suffix? "." subject))
|
||||||
|
(string-contains subject ".")
|
||||||
|
(every label-valid? (string-split subject #\.))))
|
||||||
|
|
||||||
|
(define (edge-certificate-subjects-validated edge tribes)
|
||||||
(let* ((subjects (edge-certificate-subjects edge tribes))
|
(let* ((subjects (edge-certificate-subjects edge tribes))
|
||||||
(email (tribes-edge-configuration-certificate-email edge))
|
|
||||||
(certificate-profile
|
(certificate-profile
|
||||||
(tribes-edge-configuration-certificate-profile edge))
|
(tribes-edge-configuration-certificate-profile edge))
|
||||||
(self-signed-only? (string=? certificate-profile "self-signed")))
|
(self-signed-only? (string=? certificate-profile "self-signed"))
|
||||||
(unless email
|
(ip-subjects (filter subject-is-ip? subjects))
|
||||||
(error "edge certificate email is required"
|
(invalid-subjects (filter (lambda (subject)
|
||||||
(tribes-edge-configuration-certificate-name edge)))
|
(not (or (subject-is-ip? subject)
|
||||||
(lego-certificate-configuration
|
(subject-is-dns? subject))))
|
||||||
(name (tribes-edge-configuration-certificate-name edge))
|
subjects)))
|
||||||
(subjects subjects)
|
(when (not (null? invalid-subjects))
|
||||||
(email email)
|
(error "edge certificate subjects must be IP addresses or DNS names"
|
||||||
(profile (and (not self-signed-only?) certificate-profile))
|
invalid-subjects))
|
||||||
(listen-http
|
subjects))
|
||||||
(format #f "~a:~a"
|
|
||||||
(tribes-edge-configuration-challenge-address edge)
|
(define (edge-acme-enabled? edge)
|
||||||
(tribes-edge-configuration-challenge-port edge)))
|
(not (string=? (tribes-edge-configuration-certificate-profile edge)
|
||||||
(acme-enabled? (not self-signed-only?))
|
"self-signed")))
|
||||||
(renew-days (tribes-edge-configuration-renew-days edge))
|
|
||||||
(requirement '(haproxy))
|
(define (subject->san-entry subject)
|
||||||
(reload-services '(haproxy)))))
|
(string-append (if (subject-is-ip? subject) "IP:" "DNS:") subject))
|
||||||
|
|
||||||
|
(define (edge-bootstrap-certificate-activation edge tribes)
|
||||||
|
(let ((subjects (edge-certificate-subjects-validated edge tribes)))
|
||||||
|
(simple-service
|
||||||
|
'tribes-edge-bootstrap-certificate
|
||||||
|
activation-service-type
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils)
|
||||||
|
(ice-9 textual-ports))
|
||||||
|
(let* ((user (getpwnam #$(tribes-configuration-user tribes)))
|
||||||
|
(group (getgrnam #$(tribes-configuration-group tribes)))
|
||||||
|
(uid (passwd:uid user))
|
||||||
|
(gid (group:gid group)))
|
||||||
|
(mkdir-p #$%edge-acme-state-directory)
|
||||||
|
(chown #$%edge-acme-state-directory uid gid)
|
||||||
|
(chmod #$%edge-acme-state-directory #o700)
|
||||||
|
(unless (file-exists? #$%edge-acme-key-file)
|
||||||
|
(system* #$(file-append openssl "/bin/openssl")
|
||||||
|
"ecparam" "-name" "secp384r1" "-genkey" "-noout"
|
||||||
|
"-out" #$%edge-acme-key-file))
|
||||||
|
(chown #$%edge-acme-key-file uid gid)
|
||||||
|
(chmod #$%edge-acme-key-file #o600)
|
||||||
|
(unless (file-exists? #$%edge-haproxy-pem-file)
|
||||||
|
(let ((cert-file (string-append #$%edge-acme-state-directory
|
||||||
|
"/edge.bootstrap.crt")))
|
||||||
|
(system* #$(file-append openssl "/bin/openssl")
|
||||||
|
"req" "-new" "-x509" "-sha384"
|
||||||
|
"-key" #$%edge-acme-key-file
|
||||||
|
"-out" cert-file
|
||||||
|
"-days" "7"
|
||||||
|
"-subj" "/CN=Tribes bootstrap edge"
|
||||||
|
"-addext"
|
||||||
|
#$(string-append
|
||||||
|
"subjectAltName="
|
||||||
|
(string-join (map subject->san-entry subjects) ",")))
|
||||||
|
(call-with-output-file #$%edge-haproxy-pem-file
|
||||||
|
(lambda (port)
|
||||||
|
(display (call-with-input-file cert-file get-string-all) port)
|
||||||
|
(newline port)
|
||||||
|
(display (call-with-input-file #$%edge-acme-key-file
|
||||||
|
get-string-all) port)))
|
||||||
|
(chmod #$%edge-haproxy-pem-file #o600))))))))
|
||||||
|
|
||||||
(define (edge-cache-vcl-text edge tribes)
|
(define (edge-cache-vcl-text edge tribes)
|
||||||
(string-append
|
(string-append
|
||||||
@@ -163,6 +241,13 @@
|
|||||||
" }\n\n"
|
" }\n\n"
|
||||||
" return (pass);\n"
|
" return (pass);\n"
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
|
"sub vcl_backend_fetch {\n"
|
||||||
|
" if (bereq.url ~ \"^/api/admin/\") {\n"
|
||||||
|
" set bereq.connect_timeout = 1s;\n"
|
||||||
|
" set bereq.first_byte_timeout = 35s;\n"
|
||||||
|
" set bereq.between_bytes_timeout = 35s;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n\n"
|
||||||
"sub vcl_backend_response {\n"
|
"sub vcl_backend_response {\n"
|
||||||
" if ((bereq.method == \"GET\" || bereq.method == \"HEAD\") &&\n"
|
" if ((bereq.method == \"GET\" || bereq.method == \"HEAD\") &&\n"
|
||||||
" beresp.status >= 500 && beresp.status <= 599 &&\n"
|
" beresp.status >= 500 && beresp.status <= 599 &&\n"
|
||||||
@@ -205,14 +290,12 @@
|
|||||||
(define (edge-services config)
|
(define (edge-services config)
|
||||||
(let* ((tribes (tribes-node-configuration-tribes config))
|
(let* ((tribes (tribes-node-configuration-tribes config))
|
||||||
(edge (tribes-node-configuration-edge config))
|
(edge (tribes-node-configuration-edge config))
|
||||||
(certificate (edge-certificate-config edge tribes))
|
(_subjects (edge-certificate-subjects-validated edge tribes))
|
||||||
(cache-port (tribes-edge-configuration-cache-port edge))
|
(cache-port (tribes-edge-configuration-cache-port edge))
|
||||||
(http-port (tribes-edge-configuration-http-port edge))
|
(http-port (tribes-edge-configuration-http-port edge))
|
||||||
(https-port (tribes-edge-configuration-https-port edge)))
|
(https-port (tribes-edge-configuration-https-port edge)))
|
||||||
(list
|
(list
|
||||||
(service lego-service-type
|
(edge-bootstrap-certificate-activation edge tribes)
|
||||||
(lego-configuration
|
|
||||||
(certificates (list certificate))))
|
|
||||||
(service vinyl-service-type
|
(service vinyl-service-type
|
||||||
(list
|
(list
|
||||||
(vinyl-configuration
|
(vinyl-configuration
|
||||||
@@ -244,9 +327,29 @@
|
|||||||
(format #f "[::]:~a v6only" http-port)))
|
(format #f "[::]:~a v6only" http-port)))
|
||||||
(acme-backend
|
(acme-backend
|
||||||
(format #f "~a:~a"
|
(format #f "~a:~a"
|
||||||
(tribes-edge-configuration-challenge-address edge)
|
(or (tribes-configuration-listen-address tribes)
|
||||||
(tribes-edge-configuration-challenge-port edge)))
|
"127.0.0.1")
|
||||||
(pem-files (list (lego-certificate-full-pem certificate))))))))
|
(tribes-configuration-listen-port tribes)))
|
||||||
|
(pem-files (list %edge-haproxy-pem-file)))))))
|
||||||
|
|
||||||
|
;; Interactive toolkit installed into every node's system profile. These are
|
||||||
|
;; vanilla upstream packages an operator reaches for over SSH; shipping them in
|
||||||
|
;; the system closure means they are both present on the node and served by our
|
||||||
|
;; substitute mirror, instead of forcing a fallback to bordeaux/ci on first use.
|
||||||
|
(define %tribes-node-operator-tools
|
||||||
|
(map specification->package
|
||||||
|
'("ripgrep" "fd" "tmux" "neovim" "btop")))
|
||||||
|
|
||||||
|
(define (tribes-with-edge-acme-environment tribes edge)
|
||||||
|
(tribes-configuration
|
||||||
|
(inherit tribes)
|
||||||
|
(extra-environment-variables
|
||||||
|
(append
|
||||||
|
(tribes-configuration-extra-environment-variables tribes)
|
||||||
|
(list
|
||||||
|
(string-append "TRIBES_ACME_ENABLED="
|
||||||
|
(if (edge-acme-enabled? edge) "true" "false"))
|
||||||
|
(string-append "TRIBES_ACME_STATE_DIR=" %edge-acme-state-directory))))))
|
||||||
|
|
||||||
(define (tribes-node-bbr-services config)
|
(define (tribes-node-bbr-services config)
|
||||||
(if (tribes-node-configuration-enable-bbr? config)
|
(if (tribes-node-configuration-enable-bbr? config)
|
||||||
@@ -262,7 +365,11 @@
|
|||||||
'()))
|
'()))
|
||||||
|
|
||||||
(define (tribes-node-services config)
|
(define (tribes-node-services config)
|
||||||
(let* ((tribes (tribes-node-configuration-tribes config))
|
(let* ((base-tribes (tribes-node-configuration-tribes config))
|
||||||
|
(edge (tribes-node-configuration-edge config))
|
||||||
|
(tribes (if edge
|
||||||
|
(tribes-with-edge-acme-environment base-tribes edge)
|
||||||
|
base-tribes))
|
||||||
(plugins (tribes-configuration-plugins tribes))
|
(plugins (tribes-configuration-plugins tribes))
|
||||||
(plugin-services
|
(plugin-services
|
||||||
(append-map
|
(append-map
|
||||||
@@ -280,6 +387,9 @@
|
|||||||
(simple-service 'tribes-node-network-tools
|
(simple-service 'tribes-node-network-tools
|
||||||
profile-service-type
|
profile-service-type
|
||||||
(list nftables))
|
(list nftables))
|
||||||
|
(simple-service 'tribes-node-operator-tools
|
||||||
|
profile-service-type
|
||||||
|
%tribes-node-operator-tools)
|
||||||
(service prometheus-node-exporter-service-type
|
(service prometheus-node-exporter-service-type
|
||||||
(prometheus-node-exporter-configuration
|
(prometheus-node-exporter-configuration
|
||||||
(package prometheus-node-exporter)
|
(package prometheus-node-exporter)
|
||||||
@@ -290,6 +400,8 @@
|
|||||||
tribes))
|
tribes))
|
||||||
(tribes-node-bbr-services config)
|
(tribes-node-bbr-services config)
|
||||||
plugin-services
|
plugin-services
|
||||||
(if (tribes-node-configuration-edge config)
|
(if edge
|
||||||
(edge-services config)
|
(edge-services (tribes-node-configuration
|
||||||
|
(inherit config)
|
||||||
|
(tribes tribes)))
|
||||||
'()))))
|
'()))))
|
||||||
|
|||||||
Reference in New Issue
Block a user