Factorise Garage URIs

This commit is contained in:
Nicolas Jeannerod 2024-09-17 17:31:58 +02:00
parent 7f99fc48dd
commit 9d1f20fc1c
Signed by untrusted user: Niols
GPG key ID: 35DB9EC8886E1CB8
9 changed files with 68 additions and 29 deletions

View file

@ -1,6 +1,7 @@
{ lib, ... }: { lib, config, ... }:
let let
inherit (builtins) toString;
inherit (lib) mkOption; inherit (lib) mkOption;
inherit (lib.types) types; inherit (lib.types) types;
@ -19,9 +20,38 @@ in {
default = false; default = false;
}; };
garage = mkOption {
type = types.anything;
};
domain = mkOption {
type = types.string;
};
mastodon.enable = mkOption { type = types.bool; default = false; }; mastodon.enable = mkOption { type = types.bool; default = false; };
pixelfed.enable = mkOption { type = types.bool; default = false; }; pixelfed.enable = mkOption { type = types.bool; default = false; };
peertube.enable = mkOption { type = types.bool; default = false; }; peertube.enable = mkOption { type = types.bool; default = false; };
}; };
}; };
config.fediversity = {
garage = {
api = rec {
domain = "s3.garage.${config.fediversity.domain}";
port = 3900;
url = "http://${domain}:${toString port}";
};
rpc = rec {
port = 3901;
};
web = rec {
rootDomain = "web.garage.${config.fediversity.domain}";
port = 3902;
rootDomainAndPort = "${rootDomain}:${toString port}";
urlFor = bucket: "http://${bucket}.${rootDomainAndPort}";
};
};
};
} }

View file

@ -11,6 +11,7 @@ in
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
inherit (builtins) toString;
inherit (lib) types mkOption mkEnableOption optionalString concatStringsSep; inherit (lib) types mkOption mkEnableOption optionalString concatStringsSep;
inherit (lib.strings) escapeShellArg; inherit (lib.strings) escapeShellArg;
cfg = config.services.garage; cfg = config.services.garage;
@ -41,7 +42,7 @@ let
${optionalString corsRules.enable '' ${optionalString corsRules.enable ''
garage bucket allow --read --write --owner ${bucketArg} --key tmp garage bucket allow --read --write --owner ${bucketArg} --key tmp
# TODO: endpoin-url should not be hard-coded # TODO: endpoin-url should not be hard-coded
aws --region ${cfg.settings.s3_api.s3_region} --endpoint-url http://s3.garage.localhost:3900 s3api put-bucket-cors --bucket ${bucketArg} --cors-configuration ${corsRulesJSON} aws --region ${cfg.settings.s3_api.s3_region} --endpoint-url ${config.fediversity.garage.api.url} s3api put-bucket-cors --bucket ${bucketArg} --cors-configuration ${corsRulesJSON}
garage bucket deny --read --write --owner ${bucketArg} --key tmp garage bucket deny --read --write --owner ${bucketArg} --key tmp
''} ''}
''; '';
@ -135,19 +136,22 @@ in
virtualisation.forwardPorts = [ virtualisation.forwardPorts = [
{ {
from = "host"; from = "host";
host.port = 3901; host.port = config.fediversity.garage.rpc.port;
guest.port = 3901; guest.port = config.fediversity.garage.rpc.port;
} }
{ {
from = "host"; from = "host";
host.port = 3902; host.port = config.fediversity.garage.web.port;
guest.port = 3902; guest.port = config.fediversity.garage.web.port;
} }
]; ];
environment.systemPackages = [ pkgs.minio-client pkgs.awscli ]; environment.systemPackages = [ pkgs.minio-client pkgs.awscli ];
networking.firewall.allowedTCPPorts = [ 3901 3902 ]; networking.firewall.allowedTCPPorts = [
config.fediversity.garage.rpc.port
config.fediversity.garage.web.port
];
services.garage = { services.garage = {
enable = true; enable = true;
package = pkgs.garage_0_9; package = pkgs.garage_0_9;
@ -156,15 +160,15 @@ in
# TODO: use a secret file # TODO: use a secret file
rpc_secret = "d576c4478cc7d0d94cfc127138cbb82018b0155c037d1c827dfb6c36be5f6625"; rpc_secret = "d576c4478cc7d0d94cfc127138cbb82018b0155c037d1c827dfb6c36be5f6625";
# TODO: why does this have to be set? is there not a sensible default? # TODO: why does this have to be set? is there not a sensible default?
rpc_bind_addr = "[::]:3901"; rpc_bind_addr = "[::]:${toString config.fediversity.garage.rpc.port}";
rpc_public_addr = "[::1]:3901"; rpc_public_addr = "[::1]:${toString config.fediversity.garage.rpc.port}";
s3_api.api_bind_addr = "[::]:3900"; s3_api.api_bind_addr = "[::]:${toString config.fediversity.garage.api.port}";
s3_web.bind_addr = "[::]:3902"; s3_web.bind_addr = "[::]:${toString config.fediversity.garage.web.port}";
s3_web.root_domain = ".web.garage.localhost"; s3_web.root_domain = ".${config.fediversity.garage.web.rootDomain}";
index = "index.html"; index = "index.html";
s3_api.s3_region = "garage"; s3_api.s3_region = "garage";
s3_api.root_domain = ".s3.garage.localhost"; s3_api.root_domain = ".${config.fediversity.garage.api.domain}";
}; };
}; };
systemd.services.ensure-garage = { systemd.services.ensure-garage = {
@ -177,9 +181,9 @@ in
script = '' script = ''
set -xeuo pipefail set -xeuo pipefail
# Give garage time to start up by waiting until somethings speaks HTTP # Give Garage time to start up by waiting until somethings speaks HTTP
# behind localhost:3900. # behind Garage's API URL.
until ${pkgs.curl}/bin/curl -sio /dev/null http://localhost:3900/; do sleep 1; done until ${pkgs.curl}/bin/curl -sio /dev/null ${config.fediversity.garage.api.url}; do sleep 1; done
# XXX: this is very sensitive to being a single instance # XXX: this is very sensitive to being a single instance
# (doing the bare minimum to get garage up and running) # (doing the bare minimum to get garage up and running)

View file

@ -38,7 +38,7 @@ lib.mkIf (config.fediversity.enable && config.fediversity.mastodon.enable) {
extraConfig = rec { extraConfig = rec {
S3_ENABLED = "true"; S3_ENABLED = "true";
# TODO: this shouldn't be hard-coded, it should come from the garage configuration # TODO: this shouldn't be hard-coded, it should come from the garage configuration
S3_ENDPOINT = "http://s3.garage.localhost:3900"; S3_ENDPOINT = config.fediversity.garage.api.url;
S3_REGION = "garage"; S3_REGION = "garage";
S3_BUCKET = "mastodon"; S3_BUCKET = "mastodon";
# use <S3_BUCKET>.<S3_ENDPOINT> # use <S3_BUCKET>.<S3_ENDPOINT>
@ -46,7 +46,7 @@ lib.mkIf (config.fediversity.enable && config.fediversity.mastodon.enable) {
AWS_ACCESS_KEY_ID = snakeoil_key.id; AWS_ACCESS_KEY_ID = snakeoil_key.id;
AWS_SECRET_ACCESS_KEY = snakeoil_key.secret; AWS_SECRET_ACCESS_KEY = snakeoil_key.secret;
S3_PROTOCOL = "http"; S3_PROTOCOL = "http";
S3_HOSTNAME = "web.garage.localhost:3902"; S3_HOSTNAME = config.fediversity.garage.web.rootDomainAndPort;
# by default it tries to use "<S3_HOSTNAME>/<S3_BUCKET>" # by default it tries to use "<S3_HOSTNAME>/<S3_BUCKET>"
S3_ALIAS_HOST = "${S3_BUCKET}.${S3_HOSTNAME}"; S3_ALIAS_HOST = "${S3_BUCKET}.${S3_HOSTNAME}";
# SEE: the last section in https://docs.joinmastodon.org/admin/optional/object-storage/ # SEE: the last section in https://docs.joinmastodon.org/admin/optional/object-storage/

View file

@ -56,27 +56,27 @@ lib.mkIf (config.fediversity.enable && config.fediversity.peertube.enable) {
settings = { settings = {
object_storage = { object_storage = {
enabled = true; enabled = true;
endpoint = "http://s3.garage.localhost:3900"; endpoint = config.fediversity.garage.api.url;
region = "garage"; region = "garage";
# not supported by garage # not supported by garage
# SEE: https://garagehq.deuxfleurs.fr/documentation/connect/apps/#peertube # SEE: https://garagehq.deuxfleurs.fr/documentation/connect/apps/#peertube
proxy.proxyify_private_files = false; proxy.proxyify_private_files = false;
web_videos = { web_videos = rec {
bucket_name = "peertube-videos"; bucket_name = "peertube-videos";
prefix = ""; prefix = "";
base_url = "http://peertube-videos.web.garage.localhost:3902"; base_url = config.fediversity.garage.web.urlFor bucket_name;
}; };
videos = { videos = rec {
bucket_name = "peertube-videos"; bucket_name = "peertube-videos";
prefix = ""; prefix = "";
base_url = "http://peertube-videos.web.garage.localhost:3902"; base_url = config.fediversity.garage.web.urlFor bucket_name;
}; };
streaming_playlists = { streaming_playlists = rec {
bucket_name = "peertube-playlists"; bucket_name = "peertube-playlists";
prefix = ""; prefix = "";
base_url = "http://peertube-playlists.web.garage.localhost:3902"; base_url = config.fediversity.garage.web.urlFor bucket_name;
}; };
}; };
}; };

View file

@ -37,7 +37,6 @@ lib.mkIf (config.fediversity.enable && config.fediversity.pixelfed.enable) {
services.pixelfed.enable = true; services.pixelfed.enable = true;
# TODO: factor these out so we're only defining e.g. s3.garage.localhost and port 3900 in one place
services.pixelfed.settings = { services.pixelfed.settings = {
# DANGEROUSLY_SET_FILESYSTEM_DRIVER = "s3"; # DANGEROUSLY_SET_FILESYSTEM_DRIVER = "s3";
FILESYSTEM_CLOUD = "s3"; FILESYSTEM_CLOUD = "s3";
@ -45,9 +44,9 @@ lib.mkIf (config.fediversity.enable && config.fediversity.pixelfed.enable) {
AWS_ACCESS_KEY_ID = snakeoil_key.id; AWS_ACCESS_KEY_ID = snakeoil_key.id;
AWS_SECRET_ACCESS_KEY = snakeoil_key.secret; AWS_SECRET_ACCESS_KEY = snakeoil_key.secret;
AWS_DEFAULT_REGION = "garage"; AWS_DEFAULT_REGION = "garage";
AWS_URL = "http://pixelfed.web.garage.localhost:3902/"; AWS_URL = config.fediversity.garage.web.urlFor "pixelfed";
AWS_BUCKET = "pixelfed"; AWS_BUCKET = "pixelfed";
AWS_ENDPOINT = "http://s3.garage.localhost:3900"; AWS_ENDPOINT = config.fediversity.garage.api.url;
AWS_USE_PATH_STYLE_ENDPOINT = false; AWS_USE_PATH_STYLE_ENDPOINT = false;
}; };

View file

@ -95,6 +95,7 @@ pkgs.nixosTest {
server.succeed("toot post --media $POST_MEDIA") server.succeed("toot post --media $POST_MEDIA")
with subtest("access garage"): with subtest("access garage"):
## REVIEW: could we grab `config.fediversity.garage.api.url` here in some way?
server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY") server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY")
server.succeed("mc ls garage/mastodon") server.succeed("mc ls garage/mastodon")
@ -121,6 +122,7 @@ pkgs.nixosTest {
raise Exception("mastodon did not send a content security policy header") raise Exception("mastodon did not send a content security policy header")
csp = csp_match.group(1) csp = csp_match.group(1)
# the img-src content security policy should include the garage server # the img-src content security policy should include the garage server
## REVIEW: could we grab `config.fediversity.garage.web.url` here in some way?
garage_csp = re.match(".*; img-src[^;]*web\.garage\.localhost:3902.*", csp) garage_csp = re.match(".*; img-src[^;]*web\.garage\.localhost:3902.*", csp)
if garage_csp is None: if garage_csp is None:
raise Exception("Mastodon's content security policy does not include garage server. image will not be displayed properly on mastodon.") raise Exception("Mastodon's content security policy does not include garage server. image will not be displayed properly on mastodon.")

View file

@ -186,6 +186,7 @@ pkgs.nixosTest {
raise Exception("cannot detect the uploaded image on pixelfed page.") raise Exception("cannot detect the uploaded image on pixelfed page.")
with subtest("access garage"): with subtest("access garage"):
## REVIEW: could we grab `config.fediversity.garage.api.url` here in some way?
server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY") server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY")
server.succeed("mc ls garage/pixelfed") server.succeed("mc ls garage/pixelfed")
@ -202,6 +203,7 @@ pkgs.nixosTest {
with subtest("Check that image comes from garage"): with subtest("Check that image comes from garage"):
src = server.succeed("su - selenium -c 'selenium-script-get-src ${email} ${password}'") src = server.succeed("su - selenium -c 'selenium-script-get-src ${email} ${password}'")
## REVIEW: could we grab `config.fediversity.garage.web.url` here in some way?
if not src.startswith("http://pixelfed.web.garage.localhost:3902/"): if not src.startswith("http://pixelfed.web.garage.localhost:3902/"):
raise Exception("image does not come from garage") raise Exception("image does not come from garage")
''; '';

View file

@ -9,6 +9,7 @@
{ {
fediversity = { fediversity = {
enable = true; enable = true;
domain = "localhost";
mastodon.enable = true; mastodon.enable = true;
}; };

View file

@ -7,6 +7,7 @@
fediversity = { fediversity = {
enable = true; enable = true;
domain = "localhost";
pixelfed.enable = true; pixelfed.enable = true;
}; };
@ -24,7 +25,7 @@
# I feel like this should have an `enable` option and be configured via `services.nginx` rather than mirroring those options in services.pixelfed.nginx # I feel like this should have an `enable` option and be configured via `services.nginx` rather than mirroring those options in services.pixelfed.nginx
# TODO: If that indeed makes sense, upstream it. # TODO: If that indeed makes sense, upstream it.
nginx = { nginx = {
# locations."/public/".proxyPass = "http://pixelfed.web.garage.localhost:3902/public/"; # locations."/public/".proxyPass = "${config.fediversity.garage.web.urlFor "pixelfed"}/public/";
}; };
}; };
virtualisation.memorySize = 2048; virtualisation.memorySize = 2048;