Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 80 additions & 50 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
cluster
invoke
python
refresh-users
refresh-db-config
gen-secret
shell
;
Expand Down Expand Up @@ -182,7 +182,7 @@
cluster = _self.callPackage ./pkgs/cluster.nix { };
invoke = _self.callPackage ./pkgs/invoke.nix { };
python = _self.callPackage ./pkgs/python.nix { };
refresh-users = _self.callPackage ./pkgs/refresh-users.nix { };
refresh-db-config = _self.callPackage ./pkgs/refresh-db-config.nix { };
gen-secret = _self.callPackage ./pkgs/gen-secret.nix { };

# Requires pip2nix overlay, which is managed by the flake.
Expand All @@ -204,11 +204,12 @@
settingsFormat = pkgs.formats.json { };
defaultUser = "inventree";
defaultGroup = defaultUser;
configFile = pkgs.writeText "config.yaml" (builtins.toJSON cfg.config);
usersFile = pkgs.writeText "users.json" (builtins.toJSON cfg.users);
configFormat = pkgs.formats.yaml {};
configFile = configFormat.generate "config.yaml" cfg.config;
dbConfigFile = pkgs.writeText "users.json" (builtins.toJSON {
inherit (cfg) users systemSettings;
});
inventree = pkgs.inventree;
serverBind = "${cfg.bindIp}:${toString cfg.bindPort}";
allowedHostsStr = concatStringsSep "," cfg.allowedHosts;

# Pre-compute SystemdDirectories to create the directories if they do not exists.
singletonIfPrefix = prefix: str: optional (hasPrefix prefix str) (removePrefix prefix str);
Expand Down Expand Up @@ -264,6 +265,15 @@
# '';
#};

serverBind = mkOption {
type = types.str;
default = "${cfg.bindIp}:${toString cfg.bindPort}";
example = "unix:/run/inventree/inventree.sock";
description = ''
The address and port the server will bind to.
'';
};

bindIp = mkOption {
type = types.str;
default = "127.0.0.1";
Expand All @@ -284,41 +294,6 @@
'';
};

siteUrl = mkOption {
type = types.str;
default = "";
example = "https://inventree.example.com";
description = lib.mdDoc ''
The INVENTREE_SITE_URL option defines the base URL for the
InvenTree server. This is a critical setting, and it is required
for correct operation of the server. If not specified, the
server will attempt to determine the site URL automatically -
but this may not always be correct!

The site URL is the URL that users will use to access the
InvenTree server. For example, if the server is accessible at
`https://inventree.example.com`, the site URL should be set to
`https://inventree.example.com`. Note that this is not
necessarily the same as the internal URL that the server is
running on - the internal URL will depend entirely on your
server configuration and may be obscured by a reverse proxy or
other such setup.
'';
};

allowedHosts = mkOption {
type = types.listOf types.str;
default = [];
example = ["*"];
description = lib.mdDoc ''
List of allowed hosts used to connect to the server.

If set, siteUrl is appended to this list at runtime.
If the list evaluates to empty at runtime, it defaults to allow
all (`["*"]`).
'';
};

dataDir = mkOption {
type = types.str;
default = "/var/lib/inventree";
Expand Down Expand Up @@ -358,18 +333,66 @@
};

config = mkOption {
type = types.attrs;
type = types.submodule {
freeformType = configFormat.type;
options = {
site_url = mkOption {
type = types.str;
default = "";
example = "https://inventree.example.com";
description = lib.mdDoc ''
The INVENTREE_SITE_URL option defines the base URL for the
InvenTree server. This is a critical setting, and it is required
for correct operation of the server. If not specified, the
server will attempt to determine the site URL automatically -
but this may not always be correct!

The site URL is the URL that users will use to access the
InvenTree server. For example, if the server is accessible at
`https://inventree.example.com`, the site URL should be set to
`https://inventree.example.com`. Note that this is not
necessarily the same as the internal URL that the server is
running on - the internal URL will depend entirely on your
server configuration and may be obscured by a reverse proxy or
other such setup.
'';
};
allowed_hosts = mkOption {
type = types.listOf types.str;
default = [];
example = ["*"];
description = lib.mdDoc ''
List of allowed hosts used to connect to the server.

If set, site_url is appended to this list at runtime.
If the list evaluates to empty at runtime, it defaults to allow
all (`["*"]`).
'';
};
};
};
default = { };
description = lib.mdDoc ''
Config options, see https://docs.inventree.org/en/stable/start/config/
for details
'';
};

systemSettings = mkOption {
type = types.attrsOf types.anything;
default = {};
description = lib.mdDoc ''
System settings, see https://docs.inventree.org/en/stable/settings/global/
and https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/common/setting/system.py
for details
'';
};

users = mkOption {
default = { };
description = mdDoc ''
Users which should be present on the InvenTree server
If specified, ALL OTHER USERS WILL BE DELETED
'';
example = {
admin = {
Expand Down Expand Up @@ -413,6 +436,17 @@
};
};

imports = [
(lib.mkRenamedOptionModule
[ "services" "inventree" "siteUrl" ]
[ "services" "inventree" "config" "site_url" ]
)
(lib.mkRenamedOptionModule
[ "services" "inventree" "allowedHosts" ]
[ "services" "inventree" "config" "allowed_hosts" ]
)
];

config = mkIf cfg.enable {
nixpkgs.overlays = [ self.overlays.default ];

Expand Down Expand Up @@ -447,8 +481,6 @@
wantedBy = [ "multi-user.target" ];
environment = {
INVENTREE_CONFIG_FILE = toString cfg.configPath;
INVENTREE_SITE_URL = cfg.siteUrl;
INVENTREE_ALLOWED_HOSTS = allowedHostsStr;
};
serviceConfig = systemdDirectories // {
User = defaultUser;
Expand All @@ -468,12 +500,12 @@
find . -type f -exec install -Dm 644 "{}" "${cfg.config.static_root}/{}" \;
popd

echo "Setting up users"
cat ${usersFile} | \
${inventree.refresh-users}/bin/inventree-refresh-users
echo "Setting up users and system settings"
cat ${dbConfigFile} | \
${inventree.refresh-db-config}/bin/inventree-refresh-db-config
''}";
ExecStart = ''
${inventree.server}/bin/inventree-server -b ${serverBind}
${inventree.server}/bin/inventree-server -b ${cfg.serverBind}
'';
};
};
Expand All @@ -482,8 +514,6 @@
wantedBy = [ "multi-user.target" ];
environment = {
INVENTREE_CONFIG_FILE = toString cfg.configPath;
INVENTREE_SITE_URL = cfg.siteUrl;
INVENTREE_ALLOWED_HOSTS = allowedHostsStr;
};
serviceConfig = systemdDirectories // {
User = defaultUser;
Expand Down
4 changes: 2 additions & 2 deletions pkgs/refresh-users.nix → pkgs/refresh-db-config.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
}:

let
refreshScript = writeScript "refresh_users.py" (builtins.readFile ./refresh_users.py);
refreshScript = writeScript "refresh_db_config.py" (builtins.readFile ./refresh_db_config.py);
in

writeShellApplication rec {
name = "inventree-refresh-users";
name = "inventree-refresh-db-config";
runtimeInputs = [
pythonWithPackages
src
Expand Down
90 changes: 90 additions & 0 deletions pkgs/refresh_db_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import json
import os
import sys
# This is required to pickup InvenTree.settings for some reason
sys.path.append(os.getcwd())

import django
from django.db import transaction
from django.db.utils import IntegrityError

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'InvenTree.settings')
django.setup()

from common.models import InvenTreeSetting
from django.contrib.auth import get_user_model

def _get_db_config_data():
if os.isatty(0):
print("No config data piped in, exiting")
exit(1)
_data = sys.stdin.read()
try:
data = json.loads(_data)
except json.decoder.JSONDecodeError:
print(f"Error parsing data json:\n{_data}")
exit(1)
for username, fields in data["users"].items():
email = fields["email"]
password_file = fields["password_file"]
print(
f"Reading password file for {username} ({email}) "
f"from {password_file}")
with open(password_file, "r") as f:
# Strip leading/trailing whitespace from password
fields["password"] = f.read().strip()
return data


def _commit_db_config(data):
try:
with transaction.atomic():
_commit_users(data["users"])
_commit_system_settings(data["systemSettings"])

except IntegrityError:
print("integrity error")


def _commit_users(data):
if not data:
print("No users to configure")
return

user_model = get_user_model()
print("Deleting all users")
all_users = user_model.objects.all()
print(all_users)
all_users.delete()

for username, fields in data.items():
password = fields["password"]
email = fields["email"]
is_superuser = fields.get("is_superuser", False)
# can we use kwargs to do this?
if is_superuser:
print(f"Creating superuser {username}")
new_user = user_model.objects.create_superuser(
username, email, password
)
print(f"User {new_user} was created!")
else:
print(f"Creating regular user {username}")
new_user = user_model.objects.create_user(
username, email, password
)
print(f"User {new_user} was created!")


def _commit_system_settings(settings):
for key, value in settings.items():
InvenTreeSetting.set_setting(key, value)
print(f"Setting {key}={value} was set!")

def main():
data = _get_db_config_data()
_commit_db_config(data)

if __name__ == "__main__":
main()

74 changes: 0 additions & 74 deletions pkgs/refresh_users.py

This file was deleted.

Loading