Merge pull request #104003 from felschr/feat/etebase-server

etebase-server: init at 0.7.0

Changed files
+333
nixos
modules
pkgs
development
python-modules
drf-nested-routers
servers
top-level
+1
nixos/modules/module-list.nix
···
./services/misc/domoticz.nix
./services/misc/errbot.nix
./services/misc/etcd.nix
+
./services/misc/etebase-server.nix
./services/misc/ethminer.nix
./services/misc/exhibitor.nix
./services/misc/felix.nix
+205
nixos/modules/services/misc/etebase-server.nix
···
+
{ config, pkgs, lib, ... }:
+
+
with lib;
+
+
let
+
cfg = config.services.etebase-server;
+
+
pythonEnv = pkgs.python3.withPackages (ps: with ps;
+
[ etebase-server daphne ]);
+
+
dbConfig = {
+
sqlite3 = ''
+
engine = django.db.backends.sqlite3
+
name = ${cfg.dataDir}/db.sqlite3
+
'';
+
};
+
+
defaultConfigIni = toString (pkgs.writeText "etebase-server.ini" ''
+
[global]
+
debug = false
+
secret_file = ${if cfg.secretFile != null then cfg.secretFile else ""}
+
media_root = ${cfg.dataDir}/media
+
+
[allowed_hosts]
+
allowed_host1 = ${cfg.host}
+
+
[database]
+
${dbConfig."${cfg.database.type}"}
+
'');
+
+
configIni = if cfg.customIni != null then cfg.customIni else defaultConfigIni;
+
+
defaultUser = "etebase-server";
+
in
+
{
+
options = {
+
services.etebase-server = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
example = true;
+
description = ''
+
Whether to enable the Etebase server.
+
+
Once enabled you need to create an admin user using the
+
shell command <literal>etebase-server createsuperuser</literal>.
+
Then you can login and create accounts on your-etebase-server.com/admin
+
'';
+
};
+
+
secretFile = mkOption {
+
default = null;
+
type = with types; nullOr str;
+
description = ''
+
The path to a file containing the secret
+
used as django's SECRET_KEY.
+
'';
+
};
+
+
dataDir = mkOption {
+
type = types.str;
+
default = "/var/lib/etebase-server";
+
description = "Directory to store the Etebase server data.";
+
};
+
+
port = mkOption {
+
type = with types; nullOr port;
+
default = 8001;
+
description = "Port to listen on.";
+
};
+
+
openFirewall = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Whether to open ports in the firewall for the server.
+
'';
+
};
+
+
host = mkOption {
+
type = types.str;
+
default = "0.0.0.0";
+
example = "localhost";
+
description = ''
+
Host to listen on.
+
'';
+
};
+
+
unixSocket = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
description = "The path to the socket to bind to.";
+
example = "/run/etebase-server/etebase-server.sock";
+
};
+
+
database = {
+
type = mkOption {
+
type = types.enum [ "sqlite3" ];
+
default = "sqlite3";
+
description = ''
+
Database engine to use.
+
Currently only sqlite3 is supported.
+
Other options can be configured using <literal>extraConfig</literal>.
+
'';
+
};
+
};
+
+
customIni = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
description = ''
+
Custom etebase-server.ini.
+
+
See <literal>etebase-src/etebase-server.ini.example</literal> for available options.
+
+
Setting this option overrides the default config which is generated from the options
+
<literal>secretFile</literal>, <literal>host</literal> and <literal>database</literal>.
+
'';
+
example = literalExample ''
+
[global]
+
debug = false
+
secret_file = /path/to/secret
+
media_root = /path/to/media
+
+
[allowed_hosts]
+
allowed_host1 = example.com
+
+
[database]
+
engine = django.db.backends.sqlite3
+
name = db.sqlite3
+
'';
+
};
+
+
user = mkOption {
+
type = types.str;
+
default = defaultUser;
+
description = "User under which Etebase server runs.";
+
};
+
};
+
};
+
+
config = mkIf cfg.enable {
+
+
environment.systemPackages = with pkgs; [
+
(runCommand "etebase-server" {
+
buildInputs = [ makeWrapper ];
+
} ''
+
makeWrapper ${pythonEnv}/bin/etebase-server \
+
$out/bin/etebase-server \
+
--run "cd ${cfg.dataDir}" \
+
--prefix ETEBASE_EASY_CONFIG_PATH : "${configIni}"
+
'')
+
];
+
+
systemd.tmpfiles.rules = [
+
"d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
+
];
+
+
systemd.services.etebase-server = {
+
description = "An Etebase (EteSync 2.0) server";
+
after = [ "network.target" "systemd-tmpfiles-setup.service" ];
+
wantedBy = [ "multi-user.target" ];
+
serviceConfig = {
+
User = cfg.user;
+
Restart = "always";
+
WorkingDirectory = cfg.dataDir;
+
};
+
environment = {
+
PYTHONPATH="${pythonEnv}/${pkgs.python3.sitePackages}";
+
ETEBASE_EASY_CONFIG_PATH="${configIni}";
+
};
+
preStart = ''
+
# Auto-migrate on first run or if the package has changed
+
versionFile="${cfg.dataDir}/src-version"
+
if [[ $(cat "$versionFile" 2>/dev/null) != ${pkgs.etebase-server} ]]; then
+
${pythonEnv}/bin/etebase-server migrate
+
echo ${pkgs.etebase-server} > "$versionFile"
+
fi
+
'';
+
script =
+
let
+
networking = if cfg.unixSocket != null
+
then "-u ${cfg.unixSocket}"
+
else "-b 0.0.0.0 -p ${toString cfg.port}";
+
in ''
+
cd "${pythonEnv}/lib/etebase-server";
+
${pythonEnv}/bin/daphne ${networking} \
+
etebase_server.asgi:application
+
'';
+
};
+
+
users = optionalAttrs (cfg.user == defaultUser) {
+
users.${defaultUser} = {
+
group = defaultUser;
+
home = cfg.dataDir;
+
};
+
+
groups.${defaultUser} = {};
+
};
+
+
networking.firewall = mkIf cfg.openFirewall {
+
allowedTCPPorts = [ cfg.port ];
+
};
+
};
+
}
+38
pkgs/development/python-modules/drf-nested-routers/default.nix
···
+
{ lib
+
, buildPythonPackage
+
, fetchFromGitHub
+
, setuptools
+
, django
+
, djangorestframework
+
, pytest
+
, pytest-cov
+
, pytest-django
+
, ipdb
+
, python
+
}:
+
+
buildPythonPackage rec {
+
pname = "drf-nested-routers";
+
version = "0.92.5";
+
+
src = fetchFromGitHub {
+
owner = "alanjds";
+
repo = "drf-nested-routers";
+
rev = "v${version}";
+
sha256 = "1l1jza8xz6xcm3gwxh1k6pc8fs95cq3v751gxj497y1a83d26j8i";
+
};
+
+
propagatedBuildInputs = [ django djangorestframework setuptools ];
+
checkInputs = [ pytest pytest-cov pytest-django ipdb ];
+
+
checkPhase = ''
+
${python.interpreter} runtests.py --nolint
+
'';
+
+
meta = with lib; {
+
homepage = "https://github.com/alanjds/drf-nested-routers";
+
description = "Provides routers and fields to create nested resources in the Django Rest Framework";
+
license = licenses.asl20;
+
maintainers = with maintainers; [ felschr ];
+
};
+
}
+57
pkgs/servers/etebase/default.nix
···
+
{ lib, stdenv, python3, fetchFromGitHub }:
+
+
let
+
py = python3.override {
+
packageOverrides = self: super: {
+
django = super.django_3;
+
};
+
};
+
in
+
with py.pkgs;
+
+
buildPythonPackage rec {
+
pname = "etebase-server";
+
version = "0.7.0";
+
format = "pyproject";
+
+
src = fetchFromGitHub {
+
owner = "etesync";
+
repo = "server";
+
rev = "v${version}";
+
sha256 = "1r2a7ki9w2h3l6rwqa3fzxjlqfj2lbgfrm8lynjhvcdv02s5abbi";
+
};
+
+
patches = [ ./secret.patch ];
+
+
propagatedBuildInputs = with pythonPackages; [
+
asgiref
+
cffi
+
django
+
django-cors-headers
+
djangorestframework
+
drf-nested-routers
+
msgpack
+
psycopg2
+
pycparser
+
pynacl
+
pytz
+
six
+
sqlparse
+
];
+
+
installPhase = ''
+
mkdir -p $out/bin $out/lib
+
cp -r . $out/lib/etebase-server
+
ln -s $out/lib/etebase-server/manage.py $out/bin/etebase-server
+
wrapProgram $out/bin/etebase-server --prefix PYTHONPATH : "$PYTHONPATH"
+
chmod +x $out/bin/etebase-server
+
'';
+
+
meta = with lib; {
+
homepage = "https://github.com/etesync/server";
+
description = "An Etebase (EteSync 2.0) server so you can run your own.";
+
license = licenses.agpl3Only;
+
maintainers = with maintainers; [ felschr ];
+
broken = stdenv.isDarwin;
+
};
+
}
+26
pkgs/servers/etebase/secret.patch
···
+
diff --git a/etebase_server/settings.py b/etebase_server/settings.py
+
index 9baf8d3..501d9f6 100644
+
--- a/etebase_server/settings.py
+
+++ b/etebase_server/settings.py
+
@@ -23,11 +22,6 @@
+
# Quick-start development settings - unsuitable for production
+
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
+
+
-# SECURITY WARNING: keep the secret key used in production secret!
+
-# See secret.py for how this is generated; uses a file 'secret.txt' in the root
+
-# directory
+
-SECRET_FILE = os.path.join(BASE_DIR, "secret.txt")
+
-
+
# SECURITY WARNING: don't run with debug turned on in production!
+
DEBUG = True
+
+
@@ -143,7 +137,7 @@
+
+
section = config["global"]
+
+
- SECRET_FILE = section.get("secret_file", SECRET_FILE)
+
+ SECRET_FILE = section.get("secret_file", None)
+
STATIC_ROOT = section.get("static_root", STATIC_ROOT)
+
STATIC_URL = section.get("static_url", STATIC_URL)
+
MEDIA_ROOT = section.get("media_root", MEDIA_ROOT)
+
+2
pkgs/top-level/all-packages.nix
···
eteroj.lv2 = libsForQt5.callPackage ../applications/audio/eteroj.lv2 { };
+
etebase-server = with python3Packages; toPythonApplication etebase-server;
+
etesync-dav = callPackage ../applications/misc/etesync-dav {};
etherape = callPackage ../applications/networking/sniffers/etherape { };
+4
pkgs/top-level/python-packages.nix
···
dpkt = callPackage ../development/python-modules/dpkt { };
+
drf-nested-routers = callPackage ../development/python-modules/drf-nested-routers { };
+
drf-yasg = callPackage ../development/python-modules/drf-yasg { };
drms = callPackage ../development/python-modules/drms { };
···
etebase = callPackage ../development/python-modules/etebase {
inherit (pkgs.darwin.apple_sdk.frameworks) Security;
};
+
+
etebase-server = callPackage ../servers/etebase { };
etesync = callPackage ../development/python-modules/etesync { };