From 00458bf7347497afb89509d49519fdb45f4055df Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Fri, 27 Nov 2020 22:26:09 +0100 Subject: [PATCH 01/14] make test vms buildable by removing all mentions of ccnet-server --- mod-seafile-server.nix | 4 ++-- seafile-nixos-tests.nix | 2 +- seafile-test.nix | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 68697ae..50ad7cf 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -181,7 +181,7 @@ in ]; services.seafile-server = { - path = with pkgs; [ seafile-server.ccnet-server seafile-server.seafile-server-core ]; + path = with pkgs; [ seafile-server.seafile-server-core ]; script = '' ./seafile-server/seafile-server-latest/bin/seafile-admin start ''; @@ -197,7 +197,7 @@ in # ccnet-init must only be run once per installation, as it also generates stateful key and ID # solution: invoke it once, use result as template if [ ! -e ./ccnet/mykey.peer ]; then - ${pkgs.seafile-server.ccnet-server}/bin/ccnet-init -c ./ccnet -H 'TEMPLATEHOST' + #$ {pkgs.seafile-server.ccnet-server}/bin/ccnet-init -c ./ccnet -H 'TEMPLATEHOST' mv ./ccnet/ccnet.conf{,.template} fi diff --git a/seafile-nixos-tests.nix b/seafile-nixos-tests.nix index d1e404a..ed1122c 100644 --- a/seafile-nixos-tests.nix +++ b/seafile-nixos-tests.nix @@ -15,7 +15,7 @@ import () { (import ./default.nix) ]; - i18n.consoleKeyMap = "de"; + console.keyMap = "de"; users.mutableUsers = false; users.users.test = { isNormalUser = true; diff --git a/seafile-test.nix b/seafile-test.nix index cf624c2..c1401be 100644 --- a/seafile-test.nix +++ b/seafile-test.nix @@ -10,7 +10,7 @@ (import ./default.nix) ]; - i18n.consoleKeyMap = "de"; + console.keyMap = "de"; users.mutableUsers = false; users.users.test = { isNormalUser = true; From 86a300eaecc0926e0e6fb2a9b53d092c5e4ce5ba Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Mon, 30 Nov 2020 02:21:10 +0100 Subject: [PATCH 02/14] change seafile.conf to be generated by from an attribute set --- mod-seafile-server.nix | 105 +++++++++++++++++++++-------------------- seafile-test.nix | 2 +- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 50ad7cf..4b65806 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -2,6 +2,8 @@ with lib; let cfg = config.services.seafile-server; + seafileConfigFile = pkgs.writeText "seafile.conf" + (generators.toINI {} cfg.seafileSettings); # fix permissions at start in { @@ -12,6 +14,13 @@ in default = "/srv/seafile"; description = "where to store uploaded file data"; }; + seafileSettings = mkOption { + type = with types; attrsOf (attrsOf (oneOf [ bool int str ])); + default = {}; + description = '' + all possible seafile.conf settings + ''; + }; autorun = mkOption { type = types.bool; default = true; @@ -33,20 +42,12 @@ in default = "seafile"; description = "Database name. Not required for sqlite."; }; - password = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Database password. Use passwordFile to avoid this - being world-readable in the /nix/store. - - Not required for sqlite.''; - }; - passwordFile = mkOption { + passwordFile = mkOption { type = types.nullOr types.str; default = null; description = '' The full path to a file that contains the database password. + Not required for sqlite. ''; }; host = mkOption { @@ -172,6 +173,39 @@ in directoriesToManage = [ cfg.storagePath ]; in mkIf cfg.enable { + services.seafile-server.seafileSettings = { + library_trash.expire_days = cfg.trashExpirationTime; + fileserver = { + host = cfg.fileserverBindAddress; + port = cfg.fileserverPort; + worker_threads = cfg.fileserverWorkers; + max_indexing_threads = cfg.fileserverIndexers; + fixed_block_size = cfg.fileserverBlockSize; + }; + quota = mkIf (! isNull cfg.defaultQuota) { + default = cfg.defaultQuota; + }; + history = mkIf (! isNull cfg.fileRevisionHistoryDays) { + keep_days = cfg.fileRevisionHistoryDays; + }; + database = mkMerge [ + { + type = cfg.db.type; + } + # while just using the cfg.db set directly might be possible and + # save lines of code, I prefer hand-picking options + (mkIf (cfg.db.type == "mysql") { + host = cfg.db.host; + port = cfg.db.port; + user = cfg.db.user; + connection_charset = "utf8"; + db_name = cfg.db.dbname; + max_connections = 100; + password = "#dbpass#"; + }) + ]; + }; + systemd = { # state directory permissions managed by systemd tmpfiles.rules = [ @@ -209,48 +243,17 @@ in # seafile.conf generation - echo '[library_trash] - expire_days ${toString cfg.trashExpirationTime} - - [fileserver] - host = ${cfg.fileserverBindAddress} - port = ${toString cfg.fileserverPort} - worker_threads = ${toString cfg.fileserverWorkers} - max_indexing_threads = ${toString cfg.fileserverIndexers} - fixed_block_size = ${toString cfg.fileserverIndexers}' > ./conf/seafile.conf - - if [ ${toString (! isNull cfg.defaultQuota)} ]; then - echo '[quota]' >> ./conf/seafile.conf - echo 'default = ${toString cfg.defaultQuota}' >> ./conf/seafile.conf - fi - - if [ ${toString (! isNull cfg.fileRevisionHistoryDays)} ]; then - echo '[history]' >> ./conf/seafile.conf - echo 'keep_days = ${toString cfg.defaultQuota}' >> ./conf/seafile.conf - fi - - # seafile database settings - - if [ ${cfg.db.type} = "mysql" ]; then - echo '[database] - type = mysql - host = ${cfg.db.host} - port = ${toString cfg.db.dbport} - user = ${cfg.db.user} - connection_charset = utf8 - db_name = ${cfg.db.dbname} - max_connections = 100' >> ./conf/seafile.conf - - if [ ${toString (! isNull cfg.db.password)}; then - echo 'password = ${toString cfg.db.password}' >> ./conf/seafile.conf - else - echo "password = $(cat ${toString cfg.db.passwordFile})" >> ./conf/seafile.conf - fi - else - echo '[database] - type = sqlite' >> ./conf/seafile.conf - fi + # move seafile.conf template from nix store + cp ${seafileConfigFile} ./conf/seafile.conf + # replace placeholder secrets with real secret read from file + ${if (isNull cfg.db.passwordFile) then '' + DBPASS="$(head -n1 ${toString cfg.db.passwordFile})" + sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf + '' + else "" + } + ln -s ${pkgs.seafile-server} seafile-server ./seafile-server/seafile-server-latest/bin/seafile-admin setup ''}") diff --git a/seafile-test.nix b/seafile-test.nix index c1401be..5022de2 100644 --- a/seafile-test.nix +++ b/seafile-test.nix @@ -16,7 +16,7 @@ isNormalUser = true; extraGroups = [ "wheel" ]; #hashedPassword = "$6$SZCzE/xB$Hr9sfsJ7xAcBCoptG39cxxQk8RZfldDjjGpSngOvn9Ufex5dHBEbdncXRZnfrGATsGcYPvLi7m4wIu.f8tY9B."; - password = ""; + password = "test"; home = "/home/test"; createHome = true; }; From 65f337bd157212e0aee4075873969349289cf1ab Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Wed, 9 Dec 2020 18:54:08 +0100 Subject: [PATCH 03/14] seafile-server: 8.0.0 -> 8.0.1 --- seafile-server/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seafile-server/default.nix b/seafile-server/default.nix index 02868fb..7b32c23 100644 --- a/seafile-server/default.nix +++ b/seafile-server/default.nix @@ -28,7 +28,7 @@ , python3Packages }: let - version = "8.0.0"; + version = "8.0.1"; python = python3; pythonPackages = python3Packages; django = pythonPackages.django; @@ -56,7 +56,7 @@ let owner = "haiwen"; repo = "seafile-server"; rev = "v${version}-server"; - sha256 = "0pd1zjsw6lkpxd54ln0dz5r9zx9585nib10kvpl1vgzp61g4d223"; + sha256 = "0brjmibg1vd1v6f2ybl1xr0ivf5kc8qg7fy4h204adnc0wkvjkrf"; }; # patch to work with latest, non-vulnerable libevhtp patches = [ @@ -85,7 +85,7 @@ let owner = "haiwen"; repo = "seahub"; rev = "v${version}-server"; - sha256 = "0j7g43j7w1zb00pg4aaacdv5ycva3qf561hj9pbwh4709mbiykip"; + sha256 = "16lf88j6sjxm5scx4db4bljsbksv27xr6w9rcvcnjba0fkabrlir"; }; phases = [ "unpackPhase" "installPhase" "fixupPhase" "distPhase" ]; buildInputs = [ python pythonPackages.wrapPython ]; From bc63307993fef786c0730252eed2a4fa444eb757 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Mon, 21 Dec 2020 12:24:43 +0100 Subject: [PATCH 04/14] create required dirctory hierarchy and copy over required scripts --- seafile-server/default.nix | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/seafile-server/default.nix b/seafile-server/default.nix index 7b32c23..f5aba5d 100644 --- a/seafile-server/default.nix +++ b/seafile-server/default.nix @@ -67,6 +67,13 @@ let nativeBuildInputs = [ autoconf automake libtool pkgconfig vala autoreconfHook which pythonPackages.wrapPython ]; buildInputs = [ sqlite glib python libuuid openssl oniguruma fuse libarchive libevent libevhtp ]; propagatedBuildInputs = [ libsearpc ] ++ seahubPythonDependencies; + # copy manual to required location + postInstall = '' + mkdir $out/doc + cp ${src}/doc/*.doc $out/doc/ + ''; + # prevent doc directory from being moved to share in fixupPhase + forceShare = [ "man" "info" ]; postFixup = '' buildPythonPath $propagatedBuildInputs wrapPythonProgramsIn "$out/bin" "$out $pythonPath" @@ -123,12 +130,21 @@ stdenv.mkDerivation { buildInputs = [ seahub seafile-server-core libsearpc ] ++ lib.optional withMysql libmysqlclient; phases = [ "installPhase" "fixupPhase" "distPhase" ]; - # todo: create data directory in /srv in activation script + # create required directory structure + # Which files need to be copied is specified in the function `copy_scripts_and_libs` + # of ${seafile-server-core.src}/scripts/build/build-server.py + # The install script below has been hand crafted from that list of files and needs to be updated on new releases. installPhase = '' mkdir "$out" cd "$out" ln -s ${seahub} seahub - ln -s ${seafile-server-core} seafile-server-latest + ln -s ${seafile-server-core} seafile-server + # copy general scripts + cp ${seafile-server-core.src}/scripts/{setup-seafile.sh,setup-seafile-mysql.sh,setup-seafile-mysql.py,seafile.sh,seahub.sh,reset-admin.sh,seaf-fuse.sh,check_init_admin.py,seaf-gc.sh,seaf-fsck.sh} . + # copy update scripts (and their sql) + cp -r ${seafile-server-core.src}/scripts/upgrade . + cp -r ${seafile-server-core.src}/scripts/sql . + # copy_user_manual is already done in the postInstall hook of seafile-server-core ''; meta = with lib; { maintainers = with maintainers; [ schmittlauch ]; From cb16f19b58d450dfddb735fb8a276015c7180320 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Tue, 22 Dec 2020 12:17:03 +0100 Subject: [PATCH 05/14] try initialising mysql db --- mod-seafile-server.nix | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 4b65806..6c4a427 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -37,10 +37,20 @@ in default = "seafile"; description = "Database user name. Not required for sqlite."; }; - dbname = mkOption { + dbnameSeafile = mkOption { type = types.nullOr types.str; default = "seafile"; - description = "Database name. Not required for sqlite."; + description = "Database name for Seafile server. Not required for sqlite."; + }; + dbnameCcnet = mkOption { + type = types.nullOr types.str; + default = "seafile"; + description = "Database name for Ccnet server. Not required for sqlite."; + }; + dbnameSeahub = mkOption { + type = types.nullOr types.str; + default = "seafile"; + description = "Database name for Seahub web interface. Not required for sqlite."; }; passwordFile = mkOption { type = types.nullOr types.str; @@ -74,11 +84,11 @@ in description = "Group account under which the Seafile server runs."; }; -# name = mkOption { -# type = types.str; -# default = "Seafile"; -# description = "name of the Seafile instance, will show up in client and web interface"; -# }; + name = mkOption { + type = types.str; + default = "Seafile"; + description = "name of the Seafile instance, will show up in client and web interface"; + }; domainName = mkOption { type = types.str; @@ -239,7 +249,7 @@ in echo "[General]" > ./conf/ccnet.conf grep "^ID =" ./ccnet/ccnet.conf.template >> ./conf/ccnet.conf # outside URL - SERVICE_URL = http${if cfg.enableTLS then "s" else ""}://${cfg.domainName}:${toString cfg.externalPort} + SERVICE_URL="http${if cfg.enableTLS then "s" else ""}://${cfg.domainName}:${toString cfg.externalPort}" # seafile.conf generation @@ -254,8 +264,19 @@ in } - ln -s ${pkgs.seafile-server} seafile-server - ./seafile-server/seafile-server-latest/bin/seafile-admin setup + ln -sf ${pkgs.seafile-server} seafile-server + ./seafile-server/setup-seafile-mysql.sh \ + -n "${cfg.name}" \ + -i "${cfg.domainName}" \ + -p "${toString cfg.fileserverPort}" \ + -d "${cfg.storagePath}" \ + -o "${cfg.db.host}" \ + -t "${toString cfg.db.dbport}" \ + -u "${cfg.db.user}" \ + -w "$DBPASS" \ + -c "${cfg.db.dbnameCcnet}" \ + -s "${cfg.db.dbnameSeafile}" \ + -b "${cfg.db.dbnameSeahub}" ''}") ]; User = cfg.user; From 9dde0d319fc492944a09990a708670b53b09e199 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Thu, 21 Jan 2021 00:30:39 +0100 Subject: [PATCH 06/14] seafile-server: 8.0.1 -> 8.0.2 --- seafile-server/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seafile-server/default.nix b/seafile-server/default.nix index f5aba5d..c2e5f67 100644 --- a/seafile-server/default.nix +++ b/seafile-server/default.nix @@ -28,7 +28,7 @@ , python3Packages }: let - version = "8.0.1"; + version = "8.0.2"; python = python3; pythonPackages = python3Packages; django = pythonPackages.django; @@ -56,7 +56,7 @@ let owner = "haiwen"; repo = "seafile-server"; rev = "v${version}-server"; - sha256 = "0brjmibg1vd1v6f2ybl1xr0ivf5kc8qg7fy4h204adnc0wkvjkrf"; + sha256 = "09zzgygyxgfdx7mjzcvww7c0gv82cmfgbscssyy886sbmjw2d9kc"; }; # patch to work with latest, non-vulnerable libevhtp patches = [ @@ -92,7 +92,7 @@ let owner = "haiwen"; repo = "seahub"; rev = "v${version}-server"; - sha256 = "16lf88j6sjxm5scx4db4bljsbksv27xr6w9rcvcnjba0fkabrlir"; + sha256 = "0967nx6qk6dpk2lxydn6qzi8fwym5s0yfqja7sdh48ksk77v9hiq"; }; phases = [ "unpackPhase" "installPhase" "fixupPhase" "distPhase" ]; buildInputs = [ python pythonPackages.wrapPython ]; From 8b73ec0585292db407bfe9bf779fa28e27f882a7 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sun, 24 Jan 2021 23:13:23 +0100 Subject: [PATCH 07/14] expose python environment throug sub-attribute, for accessing python interpreter to run admin scripts --- mod-seafile-server.nix | 14 +++----------- seafile-server/default.nix | 16 +++++++++++++++- seafile-test.nix | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 6c4a427..18b274e 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -237,17 +237,8 @@ in ''}") ("${pkgs.writeShellScript "seafile-server-preStart-unprivileged" '' # stuff run as seafile user + set -x - # ccnet-init must only be run once per installation, as it also generates stateful key and ID - # solution: invoke it once, use result as template - if [ ! -e ./ccnet/mykey.peer ]; then - #$ {pkgs.seafile-server.ccnet-server}/bin/ccnet-init -c ./ccnet -H 'TEMPLATEHOST' - mv ./ccnet/ccnet.conf{,.template} - fi - - # generate actual ccnet config file - echo "[General]" > ./conf/ccnet.conf - grep "^ID =" ./ccnet/ccnet.conf.template >> ./conf/ccnet.conf # outside URL SERVICE_URL="http${if cfg.enableTLS then "s" else ""}://${cfg.domainName}:${toString cfg.externalPort}" @@ -264,8 +255,9 @@ in } + pwd ln -sf ${pkgs.seafile-server} seafile-server - ./seafile-server/setup-seafile-mysql.sh \ + ${pkgs.seafile-server.pythonEnv}/bin/python seafile-server/setup-seafile-mysql.py auto \ -n "${cfg.name}" \ -i "${cfg.domainName}" \ -p "${toString cfg.fileserverPort}" \ diff --git a/seafile-server/default.nix b/seafile-server/default.nix index c2e5f67..acb535a 100644 --- a/seafile-server/default.nix +++ b/seafile-server/default.nix @@ -49,6 +49,8 @@ let pycryptodome ] ++ map (p: p.override { inherit django; }) djangoModules; # build django modules with required version + # defining them here to be able to expose them in a python environment as well + pythonEnvDeps = seahubPythonDependencies ++ [ libsearpc ]; seafile-server-core = stdenv.mkDerivation rec { name = "seafile-server-core"; inherit version; @@ -66,7 +68,7 @@ let # `which` is called directly from python during buildPhase, so we need the binary nativeBuildInputs = [ autoconf automake libtool pkgconfig vala autoreconfHook which pythonPackages.wrapPython ]; buildInputs = [ sqlite glib python libuuid openssl oniguruma fuse libarchive libevent libevhtp ]; - propagatedBuildInputs = [ libsearpc ] ++ seahubPythonDependencies; + propagatedBuildInputs = pythonEnvDeps; # copy manual to required location postInstall = '' mkdir $out/doc @@ -127,6 +129,7 @@ stdenv.mkDerivation { name = "seafile-server"; inherit version; + nativeBuildInputs = [ python3Packages.wrapPython ]; buildInputs = [ seahub seafile-server-core libsearpc ] ++ lib.optional withMysql libmysqlclient; phases = [ "installPhase" "fixupPhase" "distPhase" ]; @@ -145,10 +148,21 @@ stdenv.mkDerivation { cp -r ${seafile-server-core.src}/scripts/upgrade . cp -r ${seafile-server-core.src}/scripts/sql . # copy_user_manual is already done in the postInstall hook of seafile-server-core + # python admin scripts need to be made executable and patched with python path + chmod ugo+x *.py + buildPythonPath $propagatedBuildInputs + wrapPythonProgramsIn "$out/*.py" "$out $pythonPath" + + echo -n "${version}" > installed_version ''; meta = with lib; { maintainers = with maintainers; [ schmittlauch ]; license = licenses.free; # components with different free software licenses are combined }; inherit seafile-server-core seahub;# for using the path in the NixOS module + + pythonEnv = python3.buildEnv.override { + extraLibs = pythonEnvDeps; + ignoreCollisions = true; + }; } diff --git a/seafile-test.nix b/seafile-test.nix index 5022de2..1bd1cb1 100644 --- a/seafile-test.nix +++ b/seafile-test.nix @@ -25,7 +25,7 @@ services.seafile-server = { enable = true; #autorun = false; - domainName = "localhost"; + domainName = "seaf.local"; }; } From 1f4e3b5c7f11998f30728467430d39c0612c089a Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Wed, 27 Jan 2021 00:45:57 +0100 Subject: [PATCH 08/14] seafile-server: 8.0.2 -> 8.0.3 --- seafile-server/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seafile-server/default.nix b/seafile-server/default.nix index acb535a..2f4d32b 100644 --- a/seafile-server/default.nix +++ b/seafile-server/default.nix @@ -28,7 +28,7 @@ , python3Packages }: let - version = "8.0.2"; + version = "8.0.3"; python = python3; pythonPackages = python3Packages; django = pythonPackages.django; @@ -58,7 +58,7 @@ let owner = "haiwen"; repo = "seafile-server"; rev = "v${version}-server"; - sha256 = "09zzgygyxgfdx7mjzcvww7c0gv82cmfgbscssyy886sbmjw2d9kc"; + sha256 = "1wmbx4smf342b5pars1zm9af2i0yaq7kjj7ry0gr337gdpa4qn3b"; }; # patch to work with latest, non-vulnerable libevhtp patches = [ @@ -94,7 +94,7 @@ let owner = "haiwen"; repo = "seahub"; rev = "v${version}-server"; - sha256 = "0967nx6qk6dpk2lxydn6qzi8fwym5s0yfqja7sdh48ksk77v9hiq"; + sha256 = "0vfkiavsmpjm6wjr5rcnmnpnb3rxr3svwk8fsh5c76zg87ckdz4d"; }; phases = [ "unpackPhase" "installPhase" "fixupPhase" "distPhase" ]; buildInputs = [ python pythonPackages.wrapPython ]; From 3429d2ea6371c5e3803a4fcbe3955bcaec23abb1 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sat, 30 Jan 2021 00:49:58 +0100 Subject: [PATCH 09/14] generate ccnet.conf --- mod-seafile-server.nix | 75 +++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 18b274e..afed153 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -4,6 +4,8 @@ let cfg = config.services.seafile-server; seafileConfigFile = pkgs.writeText "seafile.conf" (generators.toINI {} cfg.seafileSettings); + ccnetConfigFile = pkgs.writeText "ccnet.conf" + (generators.toINI {} cfg.ccnetSettings); # fix permissions at start in { @@ -14,6 +16,13 @@ in default = "/srv/seafile"; description = "where to store uploaded file data"; }; + ccnetSettings = mkOption { + type = with types; attrsOf (attrsOf (oneOf [ bool int str ])); + default = {}; + description = '' + all possible ccnet.conf settings + ''; + }; seafileSettings = mkOption { type = with types; attrsOf (attrsOf (oneOf [ bool int str ])); default = {}; @@ -183,6 +192,25 @@ in directoriesToManage = [ cfg.storagePath ]; in mkIf cfg.enable { + services.seafile-server.ccnetSettings = { + # TODO: ID and NAME might be required + General.SERVICE_URL="http${if cfg.enableTLS then "s" else ""}://${cfg.domainName}:${toString cfg.externalPort}/"; + Database = mkMerge [ + { + ENGINE = cfg.db.type; + } + (mkIf (cfg.db.type == "mysql") { + HOST = cfg.db.host; + PORT = cfg.db.port; + USER = cfg.db.user; + CONNECTION_CHARSET = "utf8"; + DB = cfg.db.dbnameCcnet; + password = "#dbpass#"; + }) + ]; + + }; + services.seafile-server.seafileSettings = { library_trash.expire_days = cfg.trashExpirationTime; fileserver = { @@ -209,7 +237,7 @@ in port = cfg.db.port; user = cfg.db.user; connection_charset = "utf8"; - db_name = cfg.db.dbname; + db_name = cfg.db.dbnameSeafile; max_connections = 100; password = "#dbpass#"; }) @@ -220,7 +248,7 @@ in # state directory permissions managed by systemd tmpfiles.rules = [ "d ${cfg.storagePath} 0750 ${cfg.user} ${cfg.group} -" - "d ${cfg.storagePath}/conf 0750 ${cfg.user} ${cfg.group} -" + "d ${cfg.storagePath}/conf 0700 ${cfg.user} ${cfg.group} -" "d ${cfg.storagePath}/home 0710 ${cfg.user} ${cfg.group} -" ]; services.seafile-server = { @@ -237,38 +265,39 @@ in ''}") ("${pkgs.writeShellScript "seafile-server-preStart-unprivileged" '' # stuff run as seafile user - set -x - - # outside URL - SERVICE_URL="http${if cfg.enableTLS then "s" else ""}://${cfg.domainName}:${toString cfg.externalPort}" + set -ex # seafile.conf generation - # move seafile.conf template from nix store + # move config templates from nix store + cp ${ccnetConfigFile} ./conf/ccnet.conf cp ${seafileConfigFile} ./conf/seafile.conf # replace placeholder secrets with real secret read from file - ${if (isNull cfg.db.passwordFile) then '' + ${if !(isNull cfg.db.passwordFile) then '' DBPASS="$(head -n1 ${toString cfg.db.passwordFile})" - sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf + sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf ./conf/ccnet.conf '' else "" } + # seahub secret key + if [ -e .seahubSecret ]; then + ${pkgs.seafile-server.pythonEnv} ${pkgs.seafile-server}/seahub/tools/secret_key_generator.py > .seahubSecret + chmod 400 .seahubSecret + fi + - pwd - ln -sf ${pkgs.seafile-server} seafile-server - ${pkgs.seafile-server.pythonEnv}/bin/python seafile-server/setup-seafile-mysql.py auto \ - -n "${cfg.name}" \ - -i "${cfg.domainName}" \ - -p "${toString cfg.fileserverPort}" \ - -d "${cfg.storagePath}" \ - -o "${cfg.db.host}" \ - -t "${toString cfg.db.dbport}" \ - -u "${cfg.db.user}" \ - -w "$DBPASS" \ - -c "${cfg.db.dbnameCcnet}" \ - -s "${cfg.db.dbnameSeafile}" \ - -b "${cfg.db.dbnameSeahub}" + # initialise db and other things needed at first run + if [ -e .initialised ]; then + #TODO: db initialisation + + touch .initialised + fi + + ln -nsf ${pkgs.seafile-server} seafile-server + + # for determining update version mismatches + cp ${pkgs.seafile-server}/installed_version . ''}") ]; User = cfg.user; From ce44d1916876fd3496381d7c11bf9a0710aa32e4 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sat, 30 Jan 2021 00:59:25 +0100 Subject: [PATCH 10/14] make test vm use mysql db --- mod-seafile-server.nix | 34 +++++++++++++++++----------------- seafile-test.nix | 4 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index afed153..5eb9dea 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -62,24 +62,24 @@ in description = "Database name for Seahub web interface. Not required for sqlite."; }; passwordFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The full path to a file that contains the database password. - Not required for sqlite. - ''; - }; - host = mkOption { - type = types.nullOr types.str; - default = "localhost"; - description = "Database host."; - }; - dbport = mkOption { - type = with types; nullOr (either int str); - default = 3306; - description = "Database port. Not required for sqlite."; - }; + type = types.nullOr types.str; + default = null; + description = '' + The full path to a file that contains the database password. + Not required for sqlite. + ''; }; + host = mkOption { + type = types.nullOr types.str; + default = "localhost"; + description = "Database host."; + }; + port = mkOption { + type = with types; nullOr (either int str); + default = 3306; + description = "Database port. Not required for sqlite."; + }; + }; user = mkOption { type = types.str; diff --git a/seafile-test.nix b/seafile-test.nix index 1bd1cb1..3dd349b 100644 --- a/seafile-test.nix +++ b/seafile-test.nix @@ -26,6 +26,10 @@ enable = true; #autorun = false; domainName = "seaf.local"; + db = { + type = "mysql"; + passwordFile = toString (pkgs.writeText "testPW" "lol"); + }; }; } From d3f1c04e724906705a0c6863c4a21ce34a7b2347 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sat, 30 Jan 2021 23:09:53 +0100 Subject: [PATCH 11/14] generate gunicorn.conf.py --- mod-seafile-server.nix | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 5eb9dea..a1aa4a9 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -6,6 +6,20 @@ let (generators.toINI {} cfg.seafileSettings); ccnetConfigFile = pkgs.writeText "ccnet.conf" (generators.toINI {} cfg.ccnetSettings); + gunicornConfigFile = pkgs.writeText "gunicorn.conf.py" + '' + import os + daemon = True + workers = 5 + # default localhost:8000 + bind = "127.0.0.1:8000" + # Pid + pids_dir = '${cfg.storagePath}/pids' + pidfile = os.path.join(pids_dir, 'seahub.pid') + # for file upload, we need a longer timeout value (default is only 30s, too short) + timeout = 1200 + limit_request_line = 8190 + ''; # fix permissions at start in { @@ -249,7 +263,7 @@ in tmpfiles.rules = [ "d ${cfg.storagePath} 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.storagePath}/conf 0700 ${cfg.user} ${cfg.group} -" - "d ${cfg.storagePath}/home 0710 ${cfg.user} ${cfg.group} -" + "d ${cfg.storagePath}/pids 0710 ${cfg.user} ${cfg.group} -" ]; services.seafile-server = { @@ -272,7 +286,9 @@ in # move config templates from nix store cp ${ccnetConfigFile} ./conf/ccnet.conf cp ${seafileConfigFile} ./conf/seafile.conf + cp ${gunicornConfigFile} ./conf/gunicorn.conf.py # replace placeholder secrets with real secret read from file + #TODO: unset -x to prevent DBPASS from being leaked in journal ${if !(isNull cfg.db.passwordFile) then '' DBPASS="$(head -n1 ${toString cfg.db.passwordFile})" sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf ./conf/ccnet.conf From cb441565197d703ac4825b2b4f06fd57f93ecb46 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sun, 31 Jan 2021 00:43:23 +0100 Subject: [PATCH 12/14] generate seafile_settings.py --- mod-seafile-server.nix | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index a1aa4a9..1f97b94 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -20,6 +20,22 @@ let timeout = 1200 limit_request_line = 8190 ''; + seahubConfigFile = pkgs.writeText "seahub_settings.py" + '' + SECRET_KEY = #seckey# + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.${if cfg.db.type == "mysql" then + "mysql" else abort "invalid db type"}', + 'NAME': '${cfg.db.dbnameSeahub}', + 'USER': '${cfg.db.user}', + 'PASSWORD': '#dbpass#', + 'HOST': '${cfg.db.host}', + 'PORT': '${toString cfg.db.port}' + } + } + ''; # fix permissions at start in { @@ -287,21 +303,26 @@ in cp ${ccnetConfigFile} ./conf/ccnet.conf cp ${seafileConfigFile} ./conf/seafile.conf cp ${gunicornConfigFile} ./conf/gunicorn.conf.py + cp ${seahubConfigFile} ./conf/seahub_settings.py + + # seahub secret key + if [ ! -e .seahubSecret ]; then + ${pkgs.seafile-server.pythonEnv}/bin/python ${pkgs.seafile-server}/seahub/tools/secret_key_generator.py > .seahubSecret + chmod 400 .seahubSecret + fi + SEAHUB_SECRET="$(head -n1 .seahubSecret)" + # TODO: check for special characters needing to be escaped + sed -e "s,#seckey#,$SEAHUB_SECRET,g" -i ./conf/seahub_settings.py + # replace placeholder secrets with real secret read from file #TODO: unset -x to prevent DBPASS from being leaked in journal ${if !(isNull cfg.db.passwordFile) then '' DBPASS="$(head -n1 ${toString cfg.db.passwordFile})" - sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf ./conf/ccnet.conf + sed -e "s,#dbpass#,$DBPASS,g" -i ./conf/seafile.conf ./conf/ccnet.conf ./conf/seahub_settings.py '' else "" } - # seahub secret key - if [ -e .seahubSecret ]; then - ${pkgs.seafile-server.pythonEnv} ${pkgs.seafile-server}/seahub/tools/secret_key_generator.py > .seahubSecret - chmod 400 .seahubSecret - fi - # initialise db and other things needed at first run if [ -e .initialised ]; then From e6fec8642ab6e8dd1b93be80c1ea8469279f2259 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sun, 31 Jan 2021 23:46:56 +0100 Subject: [PATCH 13/14] add a mysql server to test vm --- seafile-test.nix | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/seafile-test.nix b/seafile-test.nix index 3dd349b..62aeded 100644 --- a/seafile-test.nix +++ b/seafile-test.nix @@ -28,8 +28,30 @@ domainName = "seaf.local"; db = { type = "mysql"; - passwordFile = toString (pkgs.writeText "testPW" "lol"); + passwordFile = toString (pkgs.writeText "testPW" "test"); }; }; + # db backend + services.mysql = + { + enable = true; + package = pkgs.mariadb; + ensureDatabases = [ "ccnet" "seafile" "seahub" ]; + ensureUsers = [ + rec { + name = config.services.seafile-server.db.user; + ensurePermissions = { + "ccnet.*" = "ALL PRIVILEGES"; + "seafile.*" = "ALL PRIVILEGES"; + "seahub.*" = "ALL PRIVILEGES"; + }; + } + ]; + # set a password for the seafile user + initialScript = pkgs.writeText "mariadb-init.sql" '' + CREATE USER ${config.services.seafile-server.db.user}@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD("test"); + ''; + }; + } From 8ecde562476fb753e4946c76a86cbb97349d643a Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sun, 7 Feb 2021 19:59:57 +0100 Subject: [PATCH 14/14] fix ownership and mode of copied-over (config) files These files need to be owned by the copying user instead of the Nix store permissions. install takes care of that. --- mod-seafile-server.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod-seafile-server.nix b/mod-seafile-server.nix index 1f97b94..f5ae079 100644 --- a/mod-seafile-server.nix +++ b/mod-seafile-server.nix @@ -300,10 +300,10 @@ in # seafile.conf generation # move config templates from nix store - cp ${ccnetConfigFile} ./conf/ccnet.conf - cp ${seafileConfigFile} ./conf/seafile.conf - cp ${gunicornConfigFile} ./conf/gunicorn.conf.py - cp ${seahubConfigFile} ./conf/seahub_settings.py + ${pkgs.coreutils}/bin/install ${ccnetConfigFile} ./conf/ccnet.conf + ${pkgs.coreutils}/bin/install ${seafileConfigFile} ./conf/seafile.conf + ${pkgs.coreutils}/bin/install ${gunicornConfigFile} ./conf/gunicorn.conf.py + ${pkgs.coreutils}/bin/install ${seahubConfigFile} ./conf/seahub_settings.py # seahub secret key if [ ! -e .seahubSecret ]; then @@ -334,7 +334,7 @@ in ln -nsf ${pkgs.seafile-server} seafile-server # for determining update version mismatches - cp ${pkgs.seafile-server}/installed_version . + ${pkgs.coreutils}/bin/install ${pkgs.seafile-server}/installed_version . ''}") ]; User = cfg.user;