nixos/gancio: init module
This commit is contained in:
parent
0e639f2cc0
commit
f5e44554c4
@ -44,6 +44,8 @@
|
||||
|
||||
- [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr), proxy server to bypass Cloudflare protection. Available as [services.flaresolverr](#opt-services.flaresolverr.enable) service.
|
||||
|
||||
- [Gancio](https://gancio.org/), a shared agenda for local communities. Available as [services.gancio](#opt-services.gancio.enable).
|
||||
|
||||
- [Goatcounter](https://www.goatcounter.com/), Easy web analytics. No tracking of personal data. Available as [services.goatcounter](options.html#opt-services.goatcocunter.enable).
|
||||
|
||||
- [UWSM](https://github.com/Vladimir-csp/uwsm), a wayland session manager to wrap Wayland Compositors into useful systemd units such as `graphical-session.target`. Available as [programs.uwsm](#opt-programs.uwsm.enable).
|
||||
|
@ -1411,6 +1411,7 @@
|
||||
./services/web-apps/fluidd.nix
|
||||
./services/web-apps/freshrss.nix
|
||||
./services/web-apps/galene.nix
|
||||
./services/web-apps/gancio.nix
|
||||
./services/web-apps/gerrit.nix
|
||||
./services/web-apps/glance.nix
|
||||
./services/web-apps/gotify-server.nix
|
||||
|
280
nixos/modules/services/web-apps/gancio.nix
Normal file
280
nixos/modules/services/web-apps/gancio.nix
Normal file
@ -0,0 +1,280 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.gancio;
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkOption
|
||||
types
|
||||
literalExpression
|
||||
mkIf
|
||||
optional
|
||||
mapAttrsToList
|
||||
concatStringsSep
|
||||
concatMapStringsSep
|
||||
getExe
|
||||
mkMerge
|
||||
mkDefault
|
||||
;
|
||||
in
|
||||
{
|
||||
options.services.gancio = {
|
||||
enable = mkEnableOption "Gancio, a shared agenda for local communities";
|
||||
|
||||
package = mkPackageOption pkgs "gancio" { };
|
||||
|
||||
plugins = mkOption {
|
||||
type = with types; listOf package;
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.gancioPlugins.telegram-bridge ]";
|
||||
description = ''
|
||||
Paths of gancio plugins to activate (linked under $WorkingDirectory/plugins/).
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
description = "The user (and PostgreSQL database name) used to run the gancio server";
|
||||
default = "gancio";
|
||||
};
|
||||
|
||||
settings = mkOption rec {
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
hostname = mkOption {
|
||||
type = types.str;
|
||||
description = "The domain name under which the server is reachable.";
|
||||
};
|
||||
baseurl = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "/gancio";
|
||||
description = "The URL path under which the server is reachable.";
|
||||
};
|
||||
server = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost";
|
||||
example = "::";
|
||||
description = ''
|
||||
The address (IPv4, IPv6 or DNS) for the gancio server to listen on.
|
||||
'';
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 13120;
|
||||
description = ''
|
||||
Port number of the gancio server to listen on.
|
||||
'';
|
||||
};
|
||||
};
|
||||
db = {
|
||||
dialect = mkOption {
|
||||
type = types.enum [
|
||||
"sqlite"
|
||||
"postgres"
|
||||
];
|
||||
default = "sqlite";
|
||||
description = ''
|
||||
The database dialect to use
|
||||
'';
|
||||
};
|
||||
storage = mkOption {
|
||||
description = ''
|
||||
Location for the SQLite database.
|
||||
'';
|
||||
readOnly = true;
|
||||
type = types.nullOr types.str;
|
||||
default = if cfg.settings.db.dialect == "sqlite" then "/var/lib/gancio/db.sqlite" else null;
|
||||
defaultText = ''
|
||||
if cfg.settings.db.dialect == "sqlite" then "/var/lib/gancio/db.sqlite" else null
|
||||
'';
|
||||
};
|
||||
host = mkOption {
|
||||
description = ''
|
||||
Connection string for the PostgreSQL database
|
||||
'';
|
||||
readOnly = true;
|
||||
type = types.nullOr types.str;
|
||||
default = if cfg.settings.db.dialect == "postgres" then "/run/postgresql" else null;
|
||||
defaultText = ''
|
||||
if cfg.settings.db.dialect == "postgres" then "/run/postgresql" else null
|
||||
'';
|
||||
};
|
||||
database = mkOption {
|
||||
description = ''
|
||||
Name of the PostgreSQL database
|
||||
'';
|
||||
readOnly = true;
|
||||
type = types.nullOr types.str;
|
||||
default = if cfg.settings.db.dialect == "postgres" then cfg.user else null;
|
||||
defaultText = ''
|
||||
if cfg.settings.db.dialect == "postgres" then cfg.user else null
|
||||
'';
|
||||
};
|
||||
};
|
||||
log_level = mkOption {
|
||||
description = "Gancio log level.";
|
||||
type = types.enum [
|
||||
"debug"
|
||||
"info"
|
||||
"warning"
|
||||
"error"
|
||||
];
|
||||
default = "info";
|
||||
};
|
||||
# FIXME upstream proper journald logging
|
||||
log_path = mkOption {
|
||||
description = "Directory Gancio logs into";
|
||||
readOnly = true;
|
||||
type = types.str;
|
||||
default = "/var/log/gancio";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Configuration for Gancio, see <https://gancio.org/install/config> for supported values.
|
||||
'';
|
||||
};
|
||||
|
||||
userLocale = mkOption {
|
||||
type = with types; attrsOf (attrsOf (attrsOf str));
|
||||
default = { };
|
||||
example = {
|
||||
en.register.description = "My new registration page description";
|
||||
};
|
||||
description = ''
|
||||
Override default locales within gancio.
|
||||
See [https://framagit.org/les/gancio/tree/master/locales](default languages and locales).
|
||||
'';
|
||||
};
|
||||
|
||||
nginx = mkOption {
|
||||
type = types.submodule (import ../web-servers/nginx/vhost-options.nix { inherit config lib; });
|
||||
default = { };
|
||||
example = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
description = "Extra configuration for the nginx virtual host of gancio.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
users.users.gancio = lib.mkIf (cfg.user == "gancio") {
|
||||
isSystemUser = true;
|
||||
group = cfg.user;
|
||||
home = "/var/lib/gancio";
|
||||
};
|
||||
users.groups.gancio = lib.mkIf (cfg.user == "gancio") { };
|
||||
|
||||
systemd.tmpfiles.settings."10-gancio" =
|
||||
let
|
||||
rules = {
|
||||
mode = "0755";
|
||||
user = cfg.user;
|
||||
group = config.users.users.${cfg.user}.group;
|
||||
};
|
||||
in
|
||||
{
|
||||
"/var/lib/gancio/user_locale".d = rules;
|
||||
"/var/lib/gancio/plugins".d = rules;
|
||||
};
|
||||
|
||||
systemd.services.gancio =
|
||||
let
|
||||
configFile = settingsFormat.generate "gancio-config.json" cfg.settings;
|
||||
in
|
||||
{
|
||||
description = "Gancio server";
|
||||
documentation = [ "https://gancio.org/" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [
|
||||
"network.target"
|
||||
] ++ optional (cfg.settings.db.dialect == "postgres") "postgresql.service";
|
||||
|
||||
environment = {
|
||||
NODE_ENV = "production";
|
||||
};
|
||||
|
||||
preStart = ''
|
||||
# We need this so the gancio executable run by the user finds the right settings.
|
||||
ln -sf ${configFile} config.json
|
||||
|
||||
rm -f user_locale/*
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (
|
||||
l: c: "ln -sf ${settingsFormat.generate "gancio-${l}-locale.json" c} user_locale/${l}.json"
|
||||
) cfg.userLocale
|
||||
)}
|
||||
|
||||
rm -f plugins/*
|
||||
${concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/") cfg.plugins}
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${getExe cfg.package} start ${configFile}";
|
||||
StateDirectory = "gancio";
|
||||
WorkingDirectory = "/var/lib/gancio";
|
||||
LogsDirectory = "gancio";
|
||||
User = cfg.user;
|
||||
# hardening
|
||||
RestrictRealtime = true;
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectClock = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
CapabilityBoundingSet = "";
|
||||
ProtectProc = "invisible";
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = mkIf (cfg.settings.db.dialect == "postgres") {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.user ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = cfg.user;
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."${cfg.settings.hostname}" = mkMerge [
|
||||
cfg.nginx
|
||||
{
|
||||
enableACME = mkDefault true;
|
||||
forceSSL = mkDefault true;
|
||||
locations = {
|
||||
"/" = {
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri @proxy";
|
||||
};
|
||||
"@proxy" = {
|
||||
proxyWebsockets = true;
|
||||
proxyPass = "http://${cfg.settings.server.host}:${toString cfg.settings.server.port}";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
@ -365,6 +365,7 @@ in {
|
||||
ft2-clone = handleTest ./ft2-clone.nix {};
|
||||
legit = handleTest ./legit.nix {};
|
||||
mimir = handleTest ./mimir.nix {};
|
||||
gancio = handleTest ./gancio.nix {};
|
||||
garage = handleTest ./garage {};
|
||||
gemstash = handleTest ./gemstash.nix {};
|
||||
geoserver = runTest ./geoserver.nix;
|
||||
|
87
nixos/tests/gancio.nix
Normal file
87
nixos/tests/gancio.nix
Normal file
@ -0,0 +1,87 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
extraHosts = ''
|
||||
192.168.13.12 agenda.example.com
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "gancio";
|
||||
meta.maintainers = with pkgs.lib.maintainers; [ jbgi ];
|
||||
|
||||
nodes = {
|
||||
server =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.13.12";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
inherit extraHosts;
|
||||
firewall.allowedTCPPorts = [ 80 ];
|
||||
};
|
||||
environment.systemPackages = [ pkgs.gancio ];
|
||||
services.gancio = {
|
||||
enable = true;
|
||||
settings = {
|
||||
hostname = "agenda.example.com";
|
||||
db.dialect = "postgres";
|
||||
};
|
||||
plugins = [ pkgs.gancioPlugins.telegram-bridge ];
|
||||
userLocale = {
|
||||
en = {
|
||||
register = {
|
||||
description = "My new registration page description";
|
||||
};
|
||||
};
|
||||
};
|
||||
nginx = {
|
||||
enableACME = false;
|
||||
forceSSL = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.13.1";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
inherit extraHosts;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
server.wait_for_unit("postgresql")
|
||||
server.wait_for_unit("gancio")
|
||||
server.wait_for_unit("nginx")
|
||||
server.wait_for_open_port(13120)
|
||||
server.wait_for_open_port(80)
|
||||
|
||||
# Check can create user via cli
|
||||
server.succeed("cd /var/lib/gancio && sudo -u gancio gancio users create admin dummy admin")
|
||||
|
||||
# Check event list is returned
|
||||
client.wait_until_succeeds("curl --verbose --fail-with-body http://agenda.example.com/api/events", timeout=30)
|
||||
|
||||
server.shutdown()
|
||||
client.shutdown()
|
||||
'';
|
||||
}
|
||||
)
|
Loading…
Reference in New Issue
Block a user