Merge master into haskell-updates
This commit is contained in:
commit
fc9b80e7a3
@ -378,7 +378,7 @@ The staging workflow exists to batch Hydra builds of many packages together.
|
||||
It works by directing commits that cause [mass rebuilds][mass-rebuild] to a separate `staging` branch that isn't directly built by Hydra.
|
||||
Regularly, the `staging` branch is _manually_ merged into a `staging-next` branch to be built by Hydra using the [`nixpkgs:staging-next` jobset](https://hydra.nixos.org/jobset/nixpkgs/staging-next).
|
||||
The `staging-next` branch should then only receive direct commits in order to fix Hydra builds.
|
||||
Once it is verified that there are no major regressions, it is merged into `master` using [a pull requests](https://github.com/NixOS/nixpkgs/pulls?q=head%3Astaging-next).
|
||||
Once it is verified that there are no major regressions, it is merged into `master` using [a pull request](https://github.com/NixOS/nixpkgs/pulls?q=head%3Astaging-next).
|
||||
This is done manually in order to ensure it's a good use of Hydra's computing resources.
|
||||
By keeping the `staging-next` branch separate from `staging`, this batching does not block developers from merging changes into `staging`.
|
||||
|
||||
|
@ -80,6 +80,8 @@ Do _not_ use `dart run <package_name>`, as this will attempt to download depende
|
||||
|
||||
### Usage with nix-shell {#ssec-dart-applications-nix-shell}
|
||||
|
||||
#### Using dependencies from the Nix store {#ssec-dart-applications-nix-shell-deps}
|
||||
|
||||
As `buildDartApplication` provides dependencies instead of `pub get`, Dart needs to be explicitly told where to find them.
|
||||
|
||||
Run the following commands in the source directory to configure Dart appropriately.
|
||||
@ -103,6 +105,9 @@ flutter.buildFlutterApplication {
|
||||
pname = "firmware-updater";
|
||||
version = "unstable-2023-04-30";
|
||||
|
||||
# To build for the Web, use the targetFlutterPlatform argument.
|
||||
# targetFlutterPlatform = "web";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "canonical";
|
||||
repo = "firmware-updater";
|
||||
@ -117,4 +122,15 @@ flutter.buildFlutterApplication {
|
||||
|
||||
### Usage with nix-shell {#ssec-dart-flutter-nix-shell}
|
||||
|
||||
See the [Dart documentation](#ssec-dart-applications-nix-shell) for nix-shell instructions.
|
||||
Flutter-specific `nix-shell` usage notes are included here. See the [Dart documentation](#ssec-dart-applications-nix-shell) for general `nix-shell` instructions.
|
||||
|
||||
#### Entering the shell {#ssec-dart-flutter-nix-shell-enter}
|
||||
|
||||
By default, dependencies for only the `targetFlutterPlatform` are available in the
|
||||
build environment. This is useful for keeping closures small, but be problematic
|
||||
during development. It's common, for example, to build Web apps for Linux during
|
||||
development to take advantage of native features such as stateful hot reload.
|
||||
|
||||
To enter a shell with all the usual target platforms available, use the `multiShell` attribute.
|
||||
|
||||
e.g. `nix-shell '<nixpkgs>' -A fluffychat-web.multiShell`.
|
||||
|
@ -2553,6 +2553,12 @@
|
||||
githubId = 52386117;
|
||||
name = "Blusk";
|
||||
};
|
||||
bmanuel = {
|
||||
name = "Benjamin Manuel";
|
||||
email = "ben@benmanuel.com";
|
||||
github = "bmanuel";
|
||||
githubId = 3662307;
|
||||
};
|
||||
bmilanov = {
|
||||
name = "Biser Milanov";
|
||||
email = "bmilanov11+nixpkgs@gmail.com";
|
||||
@ -15504,6 +15510,16 @@
|
||||
githubId = 1891350;
|
||||
name = "Michael Raskin";
|
||||
};
|
||||
ratcornu = {
|
||||
email = "ratcornu@skaven.org";
|
||||
github = "RatCornu";
|
||||
githubId = 98173832;
|
||||
name = "Balthazar Patiachvili";
|
||||
matrix = "@ratcornu:skweel.skaven.org";
|
||||
keys = [{
|
||||
fingerprint = "1B91 F087 3D06 1319 D3D0 7F91 FA47 BDA2 6048 9ADA";
|
||||
}];
|
||||
};
|
||||
ratsclub = {
|
||||
email = "victor@freire.dev.br";
|
||||
github = "ratsclub";
|
||||
|
@ -37,6 +37,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
|
||||
The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.
|
||||
|
||||
- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable).
|
||||
|
||||
- [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable).
|
||||
|
||||
- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
|
||||
@ -112,6 +114,13 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
|
||||
- `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively.
|
||||
Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts.
|
||||
|
||||
- `multi-user.target` no longer depends on `network-online.target`.
|
||||
This will potentially break services that assumed this was the case in the past.
|
||||
This was changed for consistency with other distributions as well as improved boot times.
|
||||
|
||||
We have added a warning for services that are
|
||||
`after = [ "network-online.target" ]` but do not depend on it (e.g. using `wants`).
|
||||
|
||||
- `networking.iproute2.enable` now does not set `environment.etc."iproute2/rt_tables".text`.
|
||||
|
||||
Setting `environment.etc."iproute2/{CONFIG_FILE_NAME}".text` will override the whole configuration file instead of appending it to the upstream configuration file.
|
||||
|
@ -110,6 +110,7 @@ let
|
||||
withExtraAttrs = configuration: configuration // {
|
||||
inherit extraArgs;
|
||||
inherit (configuration._module.args) pkgs;
|
||||
inherit lib;
|
||||
extendModules = args: withExtraAttrs (configuration.extendModules args);
|
||||
};
|
||||
in
|
||||
|
@ -10,6 +10,8 @@
|
||||
, systemd
|
||||
, fakeroot
|
||||
, util-linux
|
||||
|
||||
# filesystem tools
|
||||
, dosfstools
|
||||
, mtools
|
||||
, e2fsprogs
|
||||
@ -18,8 +20,13 @@
|
||||
, btrfs-progs
|
||||
, xfsprogs
|
||||
|
||||
# compression tools
|
||||
, zstd
|
||||
, xz
|
||||
|
||||
# arguments
|
||||
, name
|
||||
, imageFileBasename
|
||||
, compression
|
||||
, fileSystems
|
||||
, partitions
|
||||
, split
|
||||
@ -52,14 +59,25 @@ let
|
||||
};
|
||||
|
||||
fileSystemTools = builtins.concatMap (f: fileSystemToolMapping."${f}") fileSystems;
|
||||
|
||||
compressionPkg = {
|
||||
"zstd" = zstd;
|
||||
"xz" = xz;
|
||||
}."${compression.algorithm}";
|
||||
|
||||
compressionCommand = {
|
||||
"zstd" = "zstd --no-progress --threads=0 -${toString compression.level}";
|
||||
"xz" = "xz --keep --verbose --threads=0 -${toString compression.level}";
|
||||
}."${compression.algorithm}";
|
||||
in
|
||||
|
||||
runCommand name
|
||||
runCommand imageFileBasename
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
systemd
|
||||
fakeroot
|
||||
util-linux
|
||||
compressionPkg
|
||||
] ++ fileSystemTools;
|
||||
} ''
|
||||
amendedRepartDefinitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
|
||||
@ -67,6 +85,7 @@ runCommand name
|
||||
mkdir -p $out
|
||||
cd $out
|
||||
|
||||
echo "Building image with systemd-repart..."
|
||||
unshare --map-root-user fakeroot systemd-repart \
|
||||
--dry-run=no \
|
||||
--empty=create \
|
||||
@ -75,6 +94,17 @@ runCommand name
|
||||
--definitions="$amendedRepartDefinitions" \
|
||||
--split="${lib.boolToString split}" \
|
||||
--json=pretty \
|
||||
image.raw \
|
||||
${imageFileBasename}.raw \
|
||||
| tee repart-output.json
|
||||
|
||||
# Compression is implemented in the same derivation as opposed to in a
|
||||
# separate derivation to allow users to save disk space. Disk images are
|
||||
# already very space intensive so we want to allow users to mitigate this.
|
||||
if ${lib.boolToString compression.enable}; then
|
||||
for f in ${imageFileBasename}*; do
|
||||
echo "Compressing $f with ${compression.algorithm}..."
|
||||
# Keep the original file when compressing and only delete it afterwards
|
||||
${compressionCommand} $f && rm $f
|
||||
done
|
||||
fi
|
||||
''
|
||||
|
@ -66,7 +66,53 @@ in
|
||||
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc "The name of the image.";
|
||||
description = lib.mdDoc ''
|
||||
Name of the image.
|
||||
|
||||
If this option is unset but config.system.image.id is set,
|
||||
config.system.image.id is used as the default value.
|
||||
'';
|
||||
};
|
||||
|
||||
version = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = config.system.image.version;
|
||||
defaultText = lib.literalExpression "config.system.image.version";
|
||||
description = lib.mdDoc "Version of the image";
|
||||
};
|
||||
|
||||
imageFileBasename = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
description = lib.mdDoc ''
|
||||
Basename of the image filename without any extension (e.g. `image_1`).
|
||||
'';
|
||||
};
|
||||
|
||||
imageFile = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
description = lib.mdDoc ''
|
||||
Filename of the image including all extensions (e.g `image_1.raw` or
|
||||
`image_1.raw.zst`).
|
||||
'';
|
||||
};
|
||||
|
||||
compression = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "Image compression");
|
||||
|
||||
algorithm = lib.mkOption {
|
||||
type = lib.types.enum [ "zstd" "xz" ];
|
||||
default = "zstd";
|
||||
description = lib.mdDoc "Compression algorithm";
|
||||
};
|
||||
|
||||
level = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
description = lib.mdDoc ''
|
||||
Compression level. The available range depends on the used algorithm.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
seed = lib.mkOption {
|
||||
@ -131,6 +177,32 @@ in
|
||||
|
||||
config = {
|
||||
|
||||
image.repart =
|
||||
let
|
||||
version = config.image.repart.version;
|
||||
versionInfix = if version != null then "_${version}" else "";
|
||||
compressionSuffix = lib.optionalString cfg.compression.enable
|
||||
{
|
||||
"zstd" = ".zst";
|
||||
"xz" = ".xz";
|
||||
}."${cfg.compression.algorithm}";
|
||||
in
|
||||
{
|
||||
name = lib.mkIf (config.system.image.id != null) (lib.mkOptionDefault config.system.image.id);
|
||||
imageFileBasename = cfg.name + versionInfix;
|
||||
imageFile = cfg.imageFileBasename + ".raw" + compressionSuffix;
|
||||
|
||||
compression = {
|
||||
# Generally default to slightly faster than default compression
|
||||
# levels under the assumption that most of the building will be done
|
||||
# for development and release builds will be customized.
|
||||
level = lib.mkOptionDefault {
|
||||
"zstd" = 3;
|
||||
"xz" = 3;
|
||||
}."${cfg.compression.algorithm}";
|
||||
};
|
||||
};
|
||||
|
||||
system.build.image =
|
||||
let
|
||||
fileSystems = lib.filter
|
||||
@ -160,7 +232,7 @@ in
|
||||
in
|
||||
pkgs.callPackage ./repart-image.nix {
|
||||
systemd = cfg.package;
|
||||
inherit (cfg) name split seed;
|
||||
inherit (cfg) imageFileBasename compression split seed;
|
||||
inherit fileSystems definitionsDirectory partitions;
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,8 @@ let
|
||||
DOCUMENTATION_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/learn.html";
|
||||
SUPPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/community.html";
|
||||
BUG_REPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://github.com/NixOS/nixpkgs/issues";
|
||||
IMAGE_ID = lib.optionalString (config.system.image.id != null) config.system.image.id;
|
||||
IMAGE_VERSION = lib.optionalString (config.system.image.version != null) config.system.image.version;
|
||||
} // lib.optionalAttrs (cfg.variant_id != null) {
|
||||
VARIANT_ID = cfg.variant_id;
|
||||
};
|
||||
@ -110,6 +112,38 @@ in
|
||||
example = "installer";
|
||||
};
|
||||
|
||||
image = {
|
||||
|
||||
id = lib.mkOption {
|
||||
type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Image identifier.
|
||||
|
||||
This corresponds to the IMAGE_ID field in os-release. See the
|
||||
upstream docs for more details on valid characters for this field:
|
||||
https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_ID=
|
||||
|
||||
You would only want to set this option if you're build NixOS appliance images.
|
||||
'';
|
||||
};
|
||||
|
||||
version = lib.mkOption {
|
||||
type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Image version.
|
||||
|
||||
This corresponds to the IMAGE_VERSION field in os-release. See the
|
||||
upstream docs for more details on valid characters for this field:
|
||||
https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_VERSION=
|
||||
|
||||
You would only want to set this option if you're build NixOS appliance images.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
stateVersion = mkOption {
|
||||
type = types.str;
|
||||
# TODO Remove this and drop the default of the option so people are forced to set it.
|
||||
|
@ -1339,6 +1339,7 @@
|
||||
./services/web-apps/restya-board.nix
|
||||
./services/web-apps/rimgo.nix
|
||||
./services/web-apps/sftpgo.nix
|
||||
./services/web-apps/suwayomi-server.nix
|
||||
./services/web-apps/rss-bridge.nix
|
||||
./services/web-apps/selfoss.nix
|
||||
./services/web-apps/shiori.nix
|
||||
|
@ -64,6 +64,7 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
systemd = {
|
||||
services.gmediarender = {
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "gmediarender server daemon";
|
||||
|
@ -26,6 +26,7 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.jmusicbot = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
description = "Discord music bot that's easy to set up and run yourself!";
|
||||
serviceConfig = mkMerge [{
|
||||
|
@ -50,6 +50,7 @@ in
|
||||
|
||||
systemd.services.spotifyd = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "sound.target" ];
|
||||
description = "spotifyd, a Spotify playing daemon";
|
||||
environment.SHELL = "/bin/sh";
|
||||
|
@ -50,6 +50,7 @@ in {
|
||||
description = "Standalone MPD Web GUI written in C";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
|
@ -268,6 +268,7 @@ in {
|
||||
systemd.services.buildbot-master = {
|
||||
description = "Buildbot Continuous Integration Server.";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = cfg.packages ++ cfg.pythonPackages python.pkgs;
|
||||
environment.PYTHONPATH = "${python.withPackages (self: cfg.pythonPackages self ++ [ package ])}/${python.sitePackages}";
|
||||
|
@ -188,6 +188,7 @@ in
|
||||
nameValuePair "gitea-runner-${escapeSystemdPath name}" {
|
||||
inherit (instance) enable;
|
||||
description = "Gitea Actions Runner";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
] ++ optionals (wantsDocker) [
|
||||
|
@ -393,6 +393,7 @@ in
|
||||
systemd.services.hydra-evaluator =
|
||||
{ wantedBy = [ "multi-user.target" ];
|
||||
requires = [ "hydra-init.service" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "hydra-init.service" "network.target" "network-online.target" ];
|
||||
path = with pkgs; [ hydra-package nettools jq ];
|
||||
restartTriggers = [ hydraConf ];
|
||||
|
@ -143,7 +143,7 @@ in
|
||||
# ConnectionTimeout = 180
|
||||
|
||||
#RemoteServiceName = gds_db
|
||||
RemoteServicePort = ${cfg.port}
|
||||
RemoteServicePort = ${toString cfg.port}
|
||||
|
||||
# randomly choose port for server Event Notification
|
||||
#RemoteAuxPort = 0
|
||||
|
@ -104,6 +104,7 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.lldap = {
|
||||
description = "Lightweight LDAP server (lldap)";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
|
@ -294,6 +294,7 @@ in {
|
||||
"man:slapd-mdb"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
|
@ -200,6 +200,7 @@ in
|
||||
};
|
||||
|
||||
systemd.services.geoclue = {
|
||||
wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
|
||||
after = lib.optionals cfg.enableWifi [ "network-online.target" ];
|
||||
# restart geoclue service when the configuration changes
|
||||
restartTriggers = [
|
||||
@ -217,6 +218,7 @@ in
|
||||
# we can't be part of a system service, and the agent should
|
||||
# be okay with the main service coming and going
|
||||
wantedBy = [ "default.target" ];
|
||||
wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
|
||||
after = lib.optionals cfg.enableWifi [ "network-online.target" ];
|
||||
unitConfig.ConditionUser = "!@system";
|
||||
serviceConfig = {
|
||||
|
@ -41,6 +41,7 @@ in
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.evcc = {
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"mosquitto.target"
|
||||
|
@ -435,6 +435,7 @@ in {
|
||||
|
||||
systemd.services.home-assistant = {
|
||||
description = "Home Assistant";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
|
||||
|
@ -84,6 +84,7 @@ in {
|
||||
systemd.services.journaldriver = {
|
||||
description = "Stackdriver Logging journal forwarder";
|
||||
script = "${pkgs.journaldriver}/bin/journaldriver";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
@ -250,6 +250,7 @@ in
|
||||
path = [ config.services.postgresql.package ];
|
||||
})
|
||||
{
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let
|
||||
|
@ -435,7 +435,7 @@ in
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = sympaSubServices;
|
||||
wants = sympaSubServices ++ [ "network-online.target" ];
|
||||
before = sympaSubServices;
|
||||
serviceConfig = sympaServiceConfig "sympa_msg";
|
||||
|
||||
|
@ -1056,6 +1056,7 @@ in {
|
||||
|
||||
systemd.targets.matrix-synapse = lib.mkIf hasWorkers {
|
||||
description = "Synapse Matrix parent target";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
@ -1071,6 +1072,7 @@ in {
|
||||
requires = optional hasLocalPostgresDB "postgresql.service";
|
||||
}
|
||||
else {
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
|
||||
requires = optional hasLocalPostgresDB "postgresql.service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
@ -41,6 +41,7 @@ in {
|
||||
# See https://github.com/aws/amazon-ssm-agent/blob/mainline/packaging/linux/amazon-ssm-agent.service
|
||||
systemd.services.amazon-ssm-agent = {
|
||||
inherit (cfg.package.meta) description;
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
@ -154,7 +154,7 @@ in
|
||||
in {
|
||||
description = "BigClown Gateway";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = mkIf config.services.mosquitto.enable [ "mosquitto.service" ];
|
||||
wants = [ "network-online.target" ] ++ lib.optional config.services.mosquitto.enable "mosquitto.service";
|
||||
after = [ "network-online.target" ];
|
||||
preStart = ''
|
||||
umask 077
|
||||
|
@ -35,6 +35,7 @@ in {
|
||||
systemd.services."domoticz" = {
|
||||
description = pkgDesc;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
|
@ -59,6 +59,7 @@ in
|
||||
|
||||
systemd.services.etesync-dav = {
|
||||
description = "etesync-dav - A CalDAV and CardDAV adapter for EteSync";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.etesync-dav ];
|
||||
|
@ -357,6 +357,7 @@ in {
|
||||
description = "${cfg.serverName} media Server";
|
||||
# Gerbera might fail if the network interface is not available on startup
|
||||
# https://github.com/gerbera/gerbera/issues/1324
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.ExecStart = "${binaryCommand} --port ${toString cfg.port} ${interfaceFlag} ${configFlag} --home ${cfg.dataDir}";
|
||||
|
@ -77,6 +77,7 @@ in {
|
||||
systemd.services.metabase = {
|
||||
description = "Metabase server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
environment = {
|
||||
MB_PLUGINS_DIR = "${dataDir}/plugins";
|
||||
|
@ -1,4 +1,4 @@
|
||||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let cfg = config.nix.sshServe;
|
||||
@ -46,7 +46,7 @@ in {
|
||||
description = "Nix SSH store user";
|
||||
isSystemUser = true;
|
||||
group = "nix-ssh";
|
||||
useDefaultShell = true;
|
||||
shell = pkgs.bashInteractive;
|
||||
};
|
||||
users.groups.nix-ssh = {};
|
||||
|
||||
|
@ -297,6 +297,7 @@ in
|
||||
wantedBy = [ "paperless-scheduler.service" ];
|
||||
before = [ "paperless-scheduler.service" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
User = cfg.user;
|
||||
Type = "oneshot";
|
||||
|
@ -84,6 +84,7 @@ in {
|
||||
# upstream service file in https://git.io/JUt4Q
|
||||
systemd.services.mackerel-agent = {
|
||||
description = "mackerel.io agent";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "nss-lookup.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = {
|
||||
|
@ -174,6 +174,7 @@ in {
|
||||
|
||||
systemd.services.alertmanager = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
preStart = ''
|
||||
${lib.getBin pkgs.envsubst}/bin/envsubst -o "/tmp/alert-manager-substituted.yaml" \
|
||||
|
@ -30,6 +30,7 @@ in
|
||||
description = "TeamViewer remote control daemon";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "network.target" "dbus.service" ];
|
||||
requires = [ "dbus.service" ];
|
||||
preStart = "mkdir -pv /var/lib/teamviewer /var/log/teamviewer";
|
||||
|
@ -59,6 +59,7 @@ in {
|
||||
in {
|
||||
description = "Telegraf Agent";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = lib.optional (config.services.telegraf.extraConfig.inputs ? procstat) pkgs.procps;
|
||||
serviceConfig = {
|
||||
|
@ -215,6 +215,7 @@ in
|
||||
systemd.services.afsd = {
|
||||
description = "AFS client";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = lib.optional (!cfg.startDisconnected) "network-online.target";
|
||||
after = singleton (if cfg.startDisconnected then "network.target" else "network-online.target");
|
||||
serviceConfig = { RemainAfterExit = true; };
|
||||
restartIfChanged = false;
|
||||
|
@ -154,7 +154,7 @@ in
|
||||
};
|
||||
|
||||
securityType = mkOption {
|
||||
type = types.str;
|
||||
type = types.enum [ "auto" "user" "domain" "ads" ];
|
||||
default = "user";
|
||||
description = lib.mdDoc "Samba security type";
|
||||
};
|
||||
|
@ -198,6 +198,7 @@ in
|
||||
'';
|
||||
in {
|
||||
description = "Bitcoin daemon";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
|
@ -47,6 +47,7 @@ in
|
||||
|
||||
systemd.services.dante = {
|
||||
description = "Dante SOCKS v4 and v5 compatible proxy server";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
@ -114,6 +114,7 @@ in {
|
||||
systemd.services.ergo = {
|
||||
description = "ergo server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
|
@ -21,6 +21,7 @@ with lib;
|
||||
RestartSec = 5;
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
};
|
||||
};
|
||||
|
@ -460,6 +460,7 @@ in {
|
||||
|
||||
systemd.services.headscale = {
|
||||
description = "headscale coordination server for Tailscale";
|
||||
wants = [ "network-online.target" ];
|
||||
after = ["network-online.target"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
restartTriggers = [configFile];
|
||||
|
@ -125,7 +125,8 @@ in
|
||||
|
||||
systemd.services.ircd-hybrid = {
|
||||
description = "IRCD Hybrid server";
|
||||
after = [ "started networking" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = "${ircdService}/bin/control start";
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ with lib;
|
||||
systemd.services.ivpn-service = {
|
||||
description = "iVPN daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network.target" ];
|
||||
wants = [ "network.target" "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"NetworkManager.service"
|
||||
|
@ -325,6 +325,9 @@ in
|
||||
"network-online.target"
|
||||
"time-sync.target"
|
||||
];
|
||||
wants = [
|
||||
"network-online.target"
|
||||
];
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
];
|
||||
@ -372,6 +375,9 @@ in
|
||||
"network-online.target"
|
||||
"time-sync.target"
|
||||
];
|
||||
wants = [
|
||||
"network-online.target"
|
||||
];
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
];
|
||||
@ -413,6 +419,7 @@ in
|
||||
"https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html"
|
||||
];
|
||||
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"time-sync.target"
|
||||
|
@ -596,6 +596,7 @@ in
|
||||
systemd.services.mosquitto = {
|
||||
description = "Mosquitto MQTT Broker Daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
|
@ -53,7 +53,7 @@ with lib;
|
||||
systemd.services.mullvad-daemon = {
|
||||
description = "Mullvad VPN daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network.target" ];
|
||||
wants = [ "network.target" "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"NetworkManager.service"
|
||||
|
@ -117,6 +117,7 @@ in
|
||||
boot.kernelModules = [ "nbd" ];
|
||||
|
||||
systemd.services.nbd-server = {
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
before = [ "multi-user.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
@ -85,6 +85,7 @@ in
|
||||
systemd.services.ocserv = {
|
||||
description = "OpenConnect SSL VPN server";
|
||||
documentation = [ "man:ocserv(8)" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "dbus.service" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
@ -92,6 +92,7 @@ in {
|
||||
|
||||
systemd.services.pleroma = {
|
||||
description = "Pleroma social network";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "postgresql.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ];
|
||||
|
@ -208,6 +208,7 @@ in
|
||||
in
|
||||
rec {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = [ cfg.package pkgs.wireguard-tools ];
|
||||
|
||||
|
@ -33,7 +33,7 @@ in {
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "systemd-modules-load.service" "network-online.target" ];
|
||||
wants = [ "network-pre.target" ];
|
||||
wants = [ "network-pre.target" "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
|
@ -110,6 +110,7 @@ in
|
||||
systemd.services.soju = {
|
||||
description = "soju IRC bouncer";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
|
@ -55,6 +55,7 @@ in {
|
||||
systemd.services.strongswan-swanctl = {
|
||||
description = "strongSwan IPsec IKEv1/IKEv2 daemon using swanctl";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = with pkgs; [ kmod iproute2 iptables util-linux ];
|
||||
environment = {
|
||||
|
@ -153,6 +153,7 @@ in
|
||||
description = "strongSwan IPSec Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = with pkgs; [ kmod iproute2 iptables util-linux ]; # XXX Linux
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
environment = {
|
||||
STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secretsFile managePlugins enabledPlugins; };
|
||||
|
@ -107,6 +107,7 @@ in
|
||||
systemd.services.syncplay = {
|
||||
description = "Syncplay Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
|
@ -119,6 +119,7 @@ in {
|
||||
systemd.services.wasabibackend = {
|
||||
description = "wasabibackend server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
environment = {
|
||||
DOTNET_PRINT_TELEMETRY_MESSAGE = "false";
|
||||
|
@ -243,6 +243,7 @@ in
|
||||
systemd.services.znc = {
|
||||
description = "ZNC Server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
|
@ -182,6 +182,7 @@ in
|
||||
systemd.services.certmgr = {
|
||||
description = "certmgr";
|
||||
path = mkIf (cfg.svcManager == "command") [ pkgs.bash ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
inherit preStart;
|
||||
|
@ -572,6 +572,7 @@ in
|
||||
description = "OAuth2 Proxy";
|
||||
path = [ cfg.package ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
|
@ -49,6 +49,7 @@ in {
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.cachix-agent = {
|
||||
description = "Cachix Deploy Agent";
|
||||
wants = [ "network-online.target" ];
|
||||
after = ["network-online.target"];
|
||||
path = [ config.nix.package ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
@ -61,6 +61,7 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.cachix-watch-store-agent = {
|
||||
description = "Cachix watch store Agent";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = [ config.nix.package ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
@ -94,6 +94,7 @@ in
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.go2rtc = {
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
];
|
||||
|
@ -974,7 +974,7 @@ in {
|
||||
# This service depends on network-online.target and is sequenced after
|
||||
# it because it requires access to the Internet to function properly.
|
||||
bindsTo = [ "akkoma-config.service" ];
|
||||
wants = [ "network-online.service" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [
|
||||
"akkoma-config.target"
|
||||
|
@ -94,6 +94,7 @@ in {
|
||||
description = "alps is a simple and extensible webmail.";
|
||||
documentation = [ "https://git.sr.ht/~migadu/alps" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
|
@ -80,6 +80,7 @@ in {
|
||||
description = "c2FmZQ-server";
|
||||
documentation = [ "https://github.com/c2FmZQ/c2FmZQ/blob/main/README.md" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
|
@ -205,6 +205,7 @@ in {
|
||||
systemd.services.code-server = {
|
||||
description = "Code server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = cfg.extraPackages;
|
||||
environment = {
|
||||
|
@ -176,6 +176,7 @@ in
|
||||
systemd.targets.healthchecks = {
|
||||
description = "Target for all Healthchecks services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
};
|
||||
|
||||
|
@ -267,6 +267,7 @@ in {
|
||||
systemd.targets.netbox = {
|
||||
description = "Target for all NetBox services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "redis-netbox.service" ];
|
||||
};
|
||||
|
||||
|
@ -159,6 +159,7 @@ in
|
||||
systemd.services.openvscode-server = {
|
||||
description = "OpenVSCode server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = cfg.extraPackages;
|
||||
environment = cfg.extraEnvironment;
|
||||
|
@ -196,6 +196,7 @@ in {
|
||||
systemd.targets.peering-manager = {
|
||||
description = "Target for all Peering Manager services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "redis-peering-manager.service" ];
|
||||
};
|
||||
|
||||
|
108
nixos/modules/services/web-apps/suwayomi-server.md
Normal file
108
nixos/modules/services/web-apps/suwayomi-server.md
Normal file
@ -0,0 +1,108 @@
|
||||
# Suwayomi-Server {#module-services-suwayomi-server}
|
||||
|
||||
A free and open source manga reader server that runs extensions built for Tachiyomi.
|
||||
|
||||
## Basic usage {#module-services-suwayomi-server-basic-usage}
|
||||
|
||||
By default, the module will execute Suwayomi-Server backend and web UI:
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.suwayomi-server = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
It runs in the systemd service named `suwayomi-server` in the data directory `/var/lib/suwayomi-server`.
|
||||
|
||||
You can change the default parameters with some other parameters:
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.suwayomi-server = {
|
||||
enable = true;
|
||||
|
||||
dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
|
||||
openFirewall = true;
|
||||
|
||||
settings = {
|
||||
server.port = 4567;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
If you want to create a desktop icon, you can activate the system tray option:
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.suwayomi-server = {
|
||||
enable = true;
|
||||
|
||||
dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
|
||||
openFirewall = true;
|
||||
|
||||
settings = {
|
||||
server.port = 4567;
|
||||
server.enableSystemTray = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Basic authentication {#module-services-suwayomi-server-basic-auth}
|
||||
|
||||
You can configure a basic authentication to the web interface with:
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.suwayomi-server = {
|
||||
enable = true;
|
||||
|
||||
openFirewall = true;
|
||||
|
||||
settings = {
|
||||
server.port = 4567;
|
||||
server = {
|
||||
basicAuthEnabled = true;
|
||||
basicAuthUsername = "username";
|
||||
|
||||
# NOTE: this is not a real upstream option
|
||||
basicAuthPasswordFile = ./path/to/the/password/file;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Extra configuration {#module-services-suwayomi-server-extra-config}
|
||||
|
||||
Not all the configuration options are available directly in this module, but you can add the other options of suwayomi-server with:
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.suwayomi-server = {
|
||||
enable = true;
|
||||
|
||||
openFirewall = true;
|
||||
|
||||
settings = {
|
||||
server = {
|
||||
port = 4567;
|
||||
autoDownloadNewChapters = false;
|
||||
maxSourcesInParallel" = 6;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
260
nixos/modules/services/web-apps/suwayomi-server.nix
Normal file
260
nixos/modules/services/web-apps/suwayomi-server.nix
Normal file
@ -0,0 +1,260 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.suwayomi-server;
|
||||
inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.suwayomi-server = {
|
||||
enable = mkEnableOption (mdDoc "Suwayomi, a free and open source manga reader server that runs extensions built for Tachiyomi.");
|
||||
|
||||
package = lib.mkPackageOptionMD pkgs "suwayomi-server" { };
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/suwayomi-server";
|
||||
example = "/var/data/mangas";
|
||||
description = mdDoc ''
|
||||
The path to the data directory in which Suwayomi-Server will download scans.
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "suwayomi";
|
||||
example = "root";
|
||||
description = mdDoc ''
|
||||
User account under which Suwayomi-Server runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "suwayomi";
|
||||
example = "medias";
|
||||
description = mdDoc ''
|
||||
Group under which Suwayomi-Server runs.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
Whether to open the firewall for the port in {option}`services.suwayomi-server.settings.server.port`.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType =
|
||||
let
|
||||
recursiveAttrsType = with types; attrsOf (nullOr (oneOf [
|
||||
str
|
||||
path
|
||||
int
|
||||
float
|
||||
bool
|
||||
(listOf str)
|
||||
(recursiveAttrsType // { description = "instances of this type recursively"; })
|
||||
]));
|
||||
in
|
||||
recursiveAttrsType;
|
||||
options = {
|
||||
server = {
|
||||
ip = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
example = "127.0.0.1";
|
||||
description = mdDoc ''
|
||||
The ip that Suwayomi will bind to.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8080;
|
||||
example = 4567;
|
||||
description = mdDoc ''
|
||||
The port that Suwayomi will listen to.
|
||||
'';
|
||||
};
|
||||
|
||||
basicAuthEnabled = mkEnableOption (mdDoc ''
|
||||
Add basic access authentication to Suwayomi-Server.
|
||||
Enabling this option is useful when hosting on a public network/the Internet
|
||||
'');
|
||||
|
||||
basicAuthUsername = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = mdDoc ''
|
||||
The username value that you have to provide when authenticating.
|
||||
'';
|
||||
};
|
||||
|
||||
# NOTE: this is not a real upstream option
|
||||
basicAuthPasswordFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
example = "/var/secrets/suwayomi-server-password";
|
||||
description = mdDoc ''
|
||||
The password file containing the value that you have to provide when authenticating.
|
||||
'';
|
||||
};
|
||||
|
||||
downloadAsCbz = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
Download chapters as `.cbz` files.
|
||||
'';
|
||||
};
|
||||
|
||||
localSourcePath = mkOption {
|
||||
type = types.path;
|
||||
default = cfg.dataDir;
|
||||
defaultText = lib.literalExpression "suwayomi-server.dataDir";
|
||||
example = "/var/data/local_mangas";
|
||||
description = mdDoc ''
|
||||
Path to the local source folder.
|
||||
'';
|
||||
};
|
||||
|
||||
systemTrayEnabled = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
Whether to enable a system tray icon, if possible.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
description = mdDoc ''
|
||||
Configuration to write to {file}`server.conf`.
|
||||
See <https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Suwayomi-Server> for more information.
|
||||
'';
|
||||
default = { };
|
||||
example = {
|
||||
server.socksProxyEnabled = true;
|
||||
server.socksProxyHost = "yourproxyhost.com";
|
||||
server.socksProxyPort = "8080";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
assertions = [{
|
||||
assertion = with cfg.settings.server; basicAuthEnabled -> (basicAuthUsername != null && basicAuthPasswordFile != null);
|
||||
message = ''
|
||||
[suwayomi-server]: the username and the password file cannot be null when the basic auth is enabled
|
||||
'';
|
||||
}];
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ];
|
||||
|
||||
users.groups = mkIf (cfg.group == "suwayomi") {
|
||||
suwayomi = { };
|
||||
};
|
||||
|
||||
users.users = mkIf (cfg.user == "suwayomi") {
|
||||
suwayomi = {
|
||||
group = cfg.group;
|
||||
# Need to set the user home because the package writes to ~/.local/Tachidesk
|
||||
home = cfg.dataDir;
|
||||
description = "Suwayomi Daemon user";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."10-suwayomi-server" = {
|
||||
"${cfg.dataDir}/.local/share/Tachidesk".d = {
|
||||
mode = "0700";
|
||||
inherit (cfg) user group;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.suwayomi-server =
|
||||
let
|
||||
flattenConfig = prefix: config:
|
||||
lib.foldl'
|
||||
lib.mergeAttrs
|
||||
{ }
|
||||
(lib.attrValues
|
||||
(lib.mapAttrs
|
||||
(k: v:
|
||||
if !(lib.isAttrs v)
|
||||
then { "${prefix}${k}" = v; }
|
||||
else flattenConfig "${prefix}${k}." v
|
||||
)
|
||||
config
|
||||
)
|
||||
);
|
||||
|
||||
# HOCON is a JSON superset that suwayomi-server use for configuration
|
||||
toHOCON = attr:
|
||||
let
|
||||
attrType = builtins.typeOf attr;
|
||||
in
|
||||
if builtins.elem attrType [ "string" "path" "int" "float" ]
|
||||
then ''"${toString attr}"''
|
||||
else if attrType == "bool"
|
||||
then lib.boolToString attr
|
||||
else if attrType == "list"
|
||||
then "[\n${lib.concatMapStringsSep ",\n" toHOCON attr}\n]"
|
||||
else # attrs, lambda, null
|
||||
throw ''
|
||||
[suwayomi-server]: invalid config value type '${attrType}'.
|
||||
'';
|
||||
|
||||
configFile = pkgs.writeText "server.conf" (lib.pipe cfg.settings [
|
||||
(settings: lib.recursiveUpdate settings {
|
||||
server.basicAuthPasswordFile = null;
|
||||
server.basicAuthPassword =
|
||||
if settings.server.basicAuthEnabled
|
||||
then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
|
||||
else null;
|
||||
})
|
||||
(flattenConfig "")
|
||||
(lib.filterAttrs (_: x: x != null))
|
||||
(lib.mapAttrsToList (name: value: ''${name} = ${toHOCON value}''))
|
||||
lib.concatLines
|
||||
]);
|
||||
|
||||
in
|
||||
{
|
||||
description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
script = ''
|
||||
${lib.optionalString cfg.settings.server.basicAuthEnabled ''
|
||||
export TACHIDESK_SERVER_BASIC_AUTH_PASSWORD="$(<${cfg.settings.server.basicAuthPasswordFile})"
|
||||
''}
|
||||
${lib.getExe pkgs.envsubst} -i ${configFile} -o ${cfg.dataDir}/.local/share/Tachidesk/server.conf
|
||||
${lib.getExe cfg.package} -Dsuwayomi.tachidesk.config.server.rootDir=${cfg.dataDir}
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
|
||||
Type = "simple";
|
||||
Restart = "on-failure";
|
||||
|
||||
StateDirectory = mkIf (cfg.dataDir == "/var/lib/suwayomi-server") "suwayomi-server";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ ratcornu ];
|
||||
doc = ./suwayomi-server.md;
|
||||
};
|
||||
}
|
@ -174,22 +174,22 @@ let
|
||||
List of path(s) to respective language(s) which are copied from the 'languages' directory.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
[(
|
||||
[
|
||||
# Let's package the German language.
|
||||
# For other languages try to replace language and country code in the download URL with your desired one.
|
||||
# Reference https://translate.wordpress.org for available translations and
|
||||
# codes.
|
||||
language-de = pkgs.stdenv.mkDerivation {
|
||||
(pkgs.stdenv.mkDerivation {
|
||||
name = "language-de";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://de.wordpress.org/wordpress-''${pkgs.wordpress.version}-de_DE.tar.gz";
|
||||
# Name is required to invalidate the hash when wordpress is updated
|
||||
name = "wordpress-''${pkgs.wordpress.version}-language-de"
|
||||
name = "wordpress-''${pkgs.wordpress.version}-language-de";
|
||||
sha256 = "sha256-dlas0rXTSV4JAl8f/UyMbig57yURRYRhTMtJwF9g8h0=";
|
||||
};
|
||||
installPhase = "mkdir -p $out; cp -r ./wp-content/languages/* $out/";
|
||||
};
|
||||
)];
|
||||
})
|
||||
];
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -71,6 +71,7 @@ in
|
||||
systemd.services.agate = {
|
||||
description = "Agate";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
|
||||
script =
|
||||
|
@ -101,6 +101,7 @@ in {
|
||||
];
|
||||
systemd.services.mighttpd2 = {
|
||||
description = "Mighttpd2 web server";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
|
@ -98,6 +98,7 @@ in
|
||||
|
||||
services.minio = {
|
||||
description = "Minio Object Storage";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
|
@ -144,6 +144,7 @@ in {
|
||||
|
||||
systemd.services.traefik = {
|
||||
description = "Traefik web server";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
startLimitIntervalSec = 86400;
|
||||
|
@ -15,6 +15,19 @@ import json
|
||||
from typing import NamedTuple, Dict, List
|
||||
from dataclasses import dataclass
|
||||
|
||||
# These values will be replaced with actual values during the package build
|
||||
EFI_SYS_MOUNT_POINT = "@efiSysMountPoint@"
|
||||
TIMEOUT = "@timeout@"
|
||||
EDITOR = bool("@editor@")
|
||||
CONSOLE_MODE = "@consoleMode@"
|
||||
BOOTSPEC_TOOLS = "@bootspecTools@"
|
||||
DISTRO_NAME = "@distroName@"
|
||||
NIX = "@nix@"
|
||||
SYSTEMD = "@systemd@"
|
||||
CONFIGURATION_LIMIT = int("@configurationLimit@")
|
||||
CAN_TOUCH_EFI_VARIABLES = "@canTouchEfiVariables@"
|
||||
GRACEFUL = "@graceful@"
|
||||
COPY_EXTRA_FILES = "@copyExtraFiles@"
|
||||
|
||||
@dataclass
|
||||
class BootSpec:
|
||||
@ -29,7 +42,6 @@ class BootSpec:
|
||||
initrdSecrets: str | None = None
|
||||
|
||||
|
||||
|
||||
libc = ctypes.CDLL("libc.so.6")
|
||||
|
||||
class SystemIdentifier(NamedTuple):
|
||||
@ -75,16 +87,16 @@ def generation_conf_filename(profile: str | None, generation: int, specialisatio
|
||||
|
||||
|
||||
def write_loader_conf(profile: str | None, generation: int, specialisation: str | None) -> None:
|
||||
with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
|
||||
if "@timeout@" != "":
|
||||
f.write("timeout @timeout@\n")
|
||||
with open(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", 'w') as f:
|
||||
if TIMEOUT != "":
|
||||
f.write(f"timeout {TIMEOUT}\n")
|
||||
f.write("default %s\n" % generation_conf_filename(profile, generation, specialisation))
|
||||
if not @editor@:
|
||||
if not EDITOR:
|
||||
f.write("editor 0\n")
|
||||
f.write("console-mode @consoleMode@\n")
|
||||
f.write(f"console-mode {CONSOLE_MODE}\n")
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
|
||||
os.rename(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf")
|
||||
|
||||
|
||||
def get_bootspec(profile: str | None, generation: int) -> BootSpec:
|
||||
@ -95,7 +107,7 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec:
|
||||
bootspec_json = json.load(boot_json_f)
|
||||
else:
|
||||
boot_json_str = subprocess.check_output([
|
||||
"@bootspecTools@/bin/synthesize",
|
||||
f"{BOOTSPEC_TOOLS}/bin/synthesize",
|
||||
"--version",
|
||||
"1",
|
||||
system_directory,
|
||||
@ -116,7 +128,7 @@ def copy_from_file(file: str, dry_run: bool = False) -> str:
|
||||
store_dir = os.path.basename(os.path.dirname(store_file_path))
|
||||
efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix)
|
||||
if not dry_run:
|
||||
copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
|
||||
copy_if_not_exists(store_file_path, f"{EFI_SYS_MOUNT_POINT}%s" % (efi_file_path))
|
||||
return efi_file_path
|
||||
|
||||
def write_entry(profile: str | None, generation: int, specialisation: str | None,
|
||||
@ -126,13 +138,14 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
|
||||
kernel = copy_from_file(bootspec.kernel)
|
||||
initrd = copy_from_file(bootspec.initrd)
|
||||
|
||||
title = "@distroName@{profile}{specialisation}".format(
|
||||
title = "{name}{profile}{specialisation}".format(
|
||||
name=DISTRO_NAME,
|
||||
profile=" [" + profile + "]" if profile else "",
|
||||
specialisation=" (%s)" % specialisation if specialisation else "")
|
||||
|
||||
try:
|
||||
if bootspec.initrdSecrets is not None:
|
||||
subprocess.check_call([bootspec.initrdSecrets, "@efiSysMountPoint@%s" % (initrd)])
|
||||
subprocess.check_call([bootspec.initrdSecrets, f"{EFI_SYS_MOUNT_POINT}%s" % (initrd)])
|
||||
except subprocess.CalledProcessError:
|
||||
if current:
|
||||
print("failed to create initrd secrets!", file=sys.stderr)
|
||||
@ -142,7 +155,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
|
||||
f'for "{title} - Configuration {generation}", an older generation', file=sys.stderr)
|
||||
print("note: this is normal after having removed "
|
||||
"or renamed a file in `boot.initrd.secrets`", file=sys.stderr)
|
||||
entry_file = "@efiSysMountPoint@/loader/entries/%s" % (
|
||||
entry_file = f"{EFI_SYS_MOUNT_POINT}/loader/entries/%s" % (
|
||||
generation_conf_filename(profile, generation, specialisation))
|
||||
tmp_path = "%s.tmp" % (entry_file)
|
||||
kernel_params = "init=%s " % bootspec.init
|
||||
@ -167,7 +180,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
|
||||
|
||||
def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
|
||||
gen_list = subprocess.check_output([
|
||||
"@nix@/bin/nix-env",
|
||||
f"{NIX}/bin/nix-env",
|
||||
"--list-generations",
|
||||
"-p",
|
||||
"/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system"),
|
||||
@ -176,7 +189,7 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
|
||||
gen_lines = gen_list.split('\n')
|
||||
gen_lines.pop()
|
||||
|
||||
configurationLimit = @configurationLimit@
|
||||
configurationLimit = CONFIGURATION_LIMIT
|
||||
configurations = [
|
||||
SystemIdentifier(
|
||||
profile=profile,
|
||||
@ -189,14 +202,14 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
|
||||
|
||||
|
||||
def remove_old_entries(gens: list[SystemIdentifier]) -> None:
|
||||
rex_profile = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
|
||||
rex_generation = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
|
||||
rex_profile = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos-(.*)-generation-.*\.conf$")
|
||||
rex_generation = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
|
||||
known_paths = []
|
||||
for gen in gens:
|
||||
bootspec = get_bootspec(gen.profile, gen.generation)
|
||||
known_paths.append(copy_from_file(bootspec.kernel, True))
|
||||
known_paths.append(copy_from_file(bootspec.initrd, True))
|
||||
for path in glob.iglob("@efiSysMountPoint@/loader/entries/nixos*-generation-[1-9]*.conf"):
|
||||
for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/loader/entries/nixos*-generation-[1-9]*.conf"):
|
||||
if rex_profile.match(path):
|
||||
prof = rex_profile.sub(r"\1", path)
|
||||
else:
|
||||
@ -207,7 +220,7 @@ def remove_old_entries(gens: list[SystemIdentifier]) -> None:
|
||||
continue
|
||||
if not (prof, gen_number, None) in gens:
|
||||
os.unlink(path)
|
||||
for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"):
|
||||
for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/*"):
|
||||
if not path in known_paths and not os.path.isdir(path):
|
||||
os.unlink(path)
|
||||
|
||||
@ -230,7 +243,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
# Since systemd version 232 a machine ID is required and it might not
|
||||
# be there on newly installed systems, so let's generate one so that
|
||||
# bootctl can find it and we can also pass it to write_entry() later.
|
||||
cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
|
||||
cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"]
|
||||
machine_id = subprocess.run(
|
||||
cmd, text=True, check=True, stdout=subprocess.PIPE
|
||||
).stdout.rstrip()
|
||||
@ -242,22 +255,22 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
# flags to pass to bootctl install/update
|
||||
bootctl_flags = []
|
||||
|
||||
if "@canTouchEfiVariables@" != "1":
|
||||
if CAN_TOUCH_EFI_VARIABLES != "1":
|
||||
bootctl_flags.append("--no-variables")
|
||||
|
||||
if "@graceful@" == "1":
|
||||
if GRACEFUL == "1":
|
||||
bootctl_flags.append("--graceful")
|
||||
|
||||
if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1":
|
||||
# bootctl uses fopen() with modes "wxe" and fails if the file exists.
|
||||
if os.path.exists("@efiSysMountPoint@/loader/loader.conf"):
|
||||
os.unlink("@efiSysMountPoint@/loader/loader.conf")
|
||||
if os.path.exists(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf"):
|
||||
os.unlink(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf")
|
||||
|
||||
subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["install"])
|
||||
subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["install"])
|
||||
else:
|
||||
# Update bootloader to latest if needed
|
||||
available_out = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[2]
|
||||
installed_out = subprocess.check_output(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@", "status"], universal_newlines=True)
|
||||
available_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", "--version"], universal_newlines=True).split()[2]
|
||||
installed_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"], universal_newlines=True)
|
||||
|
||||
# See status_binaries() in systemd bootctl.c for code which generates this
|
||||
installed_match = re.search(r"^\W+File:.*/EFI/(?:BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
|
||||
@ -276,10 +289,10 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
|
||||
if installed_version < available_version:
|
||||
print("updating systemd-boot from %s to %s" % (installed_version, available_version))
|
||||
subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["update"])
|
||||
subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["update"])
|
||||
|
||||
os.makedirs("@efiSysMountPoint@/efi/nixos", exist_ok=True)
|
||||
os.makedirs("@efiSysMountPoint@/loader/entries", exist_ok=True)
|
||||
os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos", exist_ok=True)
|
||||
os.makedirs(f"{EFI_SYS_MOUNT_POINT}/loader/entries", exist_ok=True)
|
||||
|
||||
gens = get_generations()
|
||||
for profile in get_profiles():
|
||||
@ -302,9 +315,9 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
else:
|
||||
raise e
|
||||
|
||||
for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False):
|
||||
relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/")
|
||||
actual_root = os.path.join("@efiSysMountPoint@", relative_root)
|
||||
for root, _, files in os.walk(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", topdown=False):
|
||||
relative_root = root.removeprefix(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files").removeprefix("/")
|
||||
actual_root = os.path.join(f"{EFI_SYS_MOUNT_POINT}", relative_root)
|
||||
|
||||
for file in files:
|
||||
actual_file = os.path.join(actual_root, file)
|
||||
@ -317,14 +330,14 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
os.rmdir(actual_root)
|
||||
os.rmdir(root)
|
||||
|
||||
os.makedirs("@efiSysMountPoint@/efi/nixos/.extra-files", exist_ok=True)
|
||||
os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", exist_ok=True)
|
||||
|
||||
subprocess.check_call("@copyExtraFiles@")
|
||||
subprocess.check_call(COPY_EXTRA_FILES)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description='Update @distroName@-related systemd-boot files')
|
||||
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default @distroName@ config to boot')
|
||||
parser = argparse.ArgumentParser(description=f"Update {DISTRO_NAME}-related systemd-boot files")
|
||||
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f"The default {DISTRO_NAME} config to boot")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
@ -334,9 +347,9 @@ def main() -> None:
|
||||
# it can leave the system in an unbootable state, when a crash/outage
|
||||
# happens shortly after an update. To decrease the likelihood of this
|
||||
# event sync the efi filesystem after each update.
|
||||
rc = libc.syncfs(os.open("@efiSysMountPoint@", os.O_RDONLY))
|
||||
rc = libc.syncfs(os.open(f"{EFI_SYS_MOUNT_POINT}", os.O_RDONLY))
|
||||
if rc != 0:
|
||||
print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
|
||||
print(f"could not sync {EFI_SYS_MOUNT_POINT}: {os.strerror(rc)}", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -81,7 +81,11 @@ in {
|
||||
|
||||
type = types.bool;
|
||||
|
||||
description = lib.mdDoc "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager.
|
||||
For more information about systemd-boot:
|
||||
https://www.freedesktop.org/wiki/Software/systemd/systemd-boot/
|
||||
'';
|
||||
};
|
||||
|
||||
editor = mkOption {
|
||||
|
@ -451,20 +451,37 @@ in
|
||||
cfg.services
|
||||
);
|
||||
|
||||
assertions = concatLists (
|
||||
mapAttrsToList
|
||||
(name: service:
|
||||
map (message: {
|
||||
assertion = false;
|
||||
inherit message;
|
||||
}) (concatLists [
|
||||
(optional ((builtins.elem "network-interfaces.target" service.after) || (builtins.elem "network-interfaces.target" service.wants))
|
||||
"Service '${name}.service' is using the deprecated target network-interfaces.target, which no longer exists. Using network.target is recommended instead."
|
||||
)
|
||||
])
|
||||
)
|
||||
cfg.services
|
||||
);
|
||||
assertions = let
|
||||
mkOneAssert = typeStr: name: def: {
|
||||
assertion = lib.elem "network-online.target" def.after -> lib.elem "network-online.target" (def.wants ++ def.requires ++ def.bindsTo);
|
||||
message = "${name}.${typeStr} is ordered after 'network-online.target' but doesn't depend on it";
|
||||
};
|
||||
mkAsserts = typeStr: lib.mapAttrsToList (mkOneAssert typeStr);
|
||||
mkMountAsserts = typeStr: map (m: mkOneAssert typeStr m.what m);
|
||||
in mkMerge [
|
||||
(concatLists (
|
||||
mapAttrsToList
|
||||
(name: service:
|
||||
map (message: {
|
||||
assertion = false;
|
||||
inherit message;
|
||||
}) (concatLists [
|
||||
(optional ((builtins.elem "network-interfaces.target" service.after) || (builtins.elem "network-interfaces.target" service.wants))
|
||||
"Service '${name}.service' is using the deprecated target network-interfaces.target, which no longer exists. Using network.target is recommended instead."
|
||||
)
|
||||
])
|
||||
)
|
||||
cfg.services
|
||||
))
|
||||
(mkAsserts "target" cfg.targets)
|
||||
(mkAsserts "service" cfg.services)
|
||||
(mkAsserts "socket" cfg.sockets)
|
||||
(mkAsserts "timer" cfg.timers)
|
||||
(mkAsserts "path" cfg.paths)
|
||||
(mkMountAsserts "mount" cfg.mounts)
|
||||
(mkMountAsserts "automount" cfg.automounts)
|
||||
(mkAsserts "slice" cfg.slices)
|
||||
];
|
||||
|
||||
system.build.units = cfg.units;
|
||||
|
||||
@ -641,7 +658,6 @@ in
|
||||
systemd.services.systemd-udev-settle.restartIfChanged = false; # Causes long delays in nixos-rebuild
|
||||
systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
|
||||
systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
|
||||
systemd.targets.network-online.wantedBy = [ "multi-user.target" ];
|
||||
systemd.services.systemd-importd.environment = proxy_env;
|
||||
systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138
|
||||
|
||||
|
@ -71,6 +71,7 @@ in
|
||||
|
||||
systemd.services.fetch-ec2-metadata = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = ["network-online.target"];
|
||||
path = [ pkgs.curl ];
|
||||
script = builtins.readFile ./ec2-metadata-fetcher.sh;
|
||||
|
@ -267,6 +267,7 @@ let
|
||||
};
|
||||
in {
|
||||
wantedBy = [] ++ optional (container.autoStart) "multi-user.target";
|
||||
wants = lib.optional (container.imageFile == null) "network-online.target";
|
||||
after = lib.optionals (cfg.backend == "docker") [ "docker.service" "docker.socket" ]
|
||||
# if imageFile is not set, the service needs the network to download the image from the registry
|
||||
++ lib.optionals (container.imageFile == null) [ "network-online.target" ]
|
||||
|
@ -150,26 +150,33 @@ in
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable
|
||||
{
|
||||
config =
|
||||
let
|
||||
networkConfig = ({
|
||||
dns_enabled = false;
|
||||
driver = "bridge";
|
||||
id = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
internal = false;
|
||||
ipam_options = { driver = "host-local"; };
|
||||
ipv6_enabled = false;
|
||||
name = "podman";
|
||||
network_interface = "podman0";
|
||||
subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }];
|
||||
} // cfg.defaultNetwork.settings);
|
||||
inherit (networkConfig) dns_enabled network_interface;
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ]
|
||||
++ lib.optional cfg.dockerCompat dockerCompat;
|
||||
|
||||
# https://github.com/containers/podman/blob/097cc6eb6dd8e598c0e8676d21267b4edb11e144/docs/tutorials/basic_networking.md#default-network
|
||||
environment.etc."containers/networks/podman.json" = lib.mkIf (cfg.defaultNetwork.settings != { }) {
|
||||
source = json.generate "podman.json" ({
|
||||
dns_enabled = false;
|
||||
driver = "bridge";
|
||||
id = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
internal = false;
|
||||
ipam_options = { driver = "host-local"; };
|
||||
ipv6_enabled = false;
|
||||
name = "podman";
|
||||
network_interface = "podman0";
|
||||
subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }];
|
||||
} // cfg.defaultNetwork.settings);
|
||||
source = json.generate "podman.json" networkConfig;
|
||||
};
|
||||
|
||||
# containers cannot reach aardvark-dns otherwise
|
||||
networking.firewall.interfaces.${network_interface}.allowedUDPPorts = lib.mkIf dns_enabled [ 53 ];
|
||||
|
||||
virtualisation.containers = {
|
||||
enable = true; # Enable common /etc/containers configuration
|
||||
containersConf.settings = {
|
||||
|
@ -134,6 +134,7 @@
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
peer0.systemctl("start network-online.target")
|
||||
peer0.wait_for_unit("network-online.target")
|
||||
|
||||
peer1.wait_for_unit("3proxy.service")
|
||||
|
@ -522,6 +522,7 @@ in {
|
||||
'curl --data \'{"host": "${caDomain}", "addresses": ["${nodes.acme.networking.primaryIPAddress}"]}\' http://${dnsServerIP nodes}:8055/add-a'
|
||||
)
|
||||
|
||||
acme.systemctl("start network-online.target")
|
||||
acme.wait_for_unit("network-online.target")
|
||||
acme.wait_for_unit("pebble.service")
|
||||
|
||||
|
@ -126,6 +126,7 @@
|
||||
|
||||
with subtest("Testing successful DHCP start"):
|
||||
dhcpConf.wait_for_unit("adguardhome.service")
|
||||
client.systemctl("start network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
# Test IP assignment via DHCP
|
||||
dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100")
|
||||
|
@ -587,6 +587,7 @@ in {
|
||||
nginx-globalredirect = handleTest ./nginx-globalredirect.nix {};
|
||||
nginx-http3 = handleTest ./nginx-http3.nix {};
|
||||
nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
|
||||
nginx-moreheaders = handleTest ./nginx-moreheaders.nix {};
|
||||
nginx-njs = handleTest ./nginx-njs.nix {};
|
||||
nginx-proxyprotocol = handleTest ./nginx-proxyprotocol {};
|
||||
nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
|
||||
@ -808,6 +809,7 @@ in {
|
||||
stunnel = handleTest ./stunnel.nix {};
|
||||
sudo = handleTest ./sudo.nix {};
|
||||
sudo-rs = handleTest ./sudo-rs.nix {};
|
||||
suwayomi-server = handleTest ./suwayomi-server.nix {};
|
||||
swap-file-btrfs = handleTest ./swap-file-btrfs.nix {};
|
||||
swap-partition = handleTest ./swap-partition.nix {};
|
||||
swap-random-encryption = handleTest ./swap-random-encryption.nix {};
|
||||
|
@ -8,6 +8,9 @@
|
||||
let
|
||||
rootPartitionLabel = "root";
|
||||
|
||||
imageId = "nixos-appliance";
|
||||
imageVersion = "1-rc1";
|
||||
|
||||
bootLoaderConfigPath = "/loader/entries/nixos.conf";
|
||||
kernelPath = "/EFI/nixos/kernel.efi";
|
||||
initrdPath = "/EFI/nixos/initrd.efi";
|
||||
@ -29,6 +32,9 @@ in
|
||||
# TODO(raitobezarius): revisit this when #244907 lands
|
||||
boot.loader.grub.enable = false;
|
||||
|
||||
system.image.id = imageId;
|
||||
system.image.version = imageVersion;
|
||||
|
||||
virtualisation.fileSystems = lib.mkForce {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-partlabel/${rootPartitionLabel}";
|
||||
@ -99,7 +105,7 @@ in
|
||||
"-f",
|
||||
"qcow2",
|
||||
"-b",
|
||||
"${nodes.machine.system.build.image}/image.raw",
|
||||
"${nodes.machine.system.build.image}/${nodes.machine.image.repart.imageFile}",
|
||||
"-F",
|
||||
"raw",
|
||||
tmp_disk_image.name,
|
||||
@ -108,6 +114,10 @@ in
|
||||
# Set NIX_DISK_IMAGE so that the qemu script finds the right disk image.
|
||||
os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name
|
||||
|
||||
os_release = machine.succeed("cat /etc/os-release")
|
||||
assert 'IMAGE_ID="${imageId}"' in os_release
|
||||
assert 'IMAGE_VERSION="${imageVersion}"' in os_release
|
||||
|
||||
bootctl_status = machine.succeed("bootctl status")
|
||||
assert "${bootLoaderConfigPath}" in bootctl_status
|
||||
assert "${kernelPath}" in bootctl_status
|
||||
|
@ -4,7 +4,7 @@ in {
|
||||
name = "ayatana-indicators";
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ OPNA2608 ];
|
||||
maintainers = lib.teams.lomiri.members;
|
||||
};
|
||||
|
||||
nodes.machine = { config, ... }: {
|
||||
@ -28,16 +28,34 @@ in {
|
||||
enable = true;
|
||||
packages = with pkgs; [
|
||||
ayatana-indicator-messages
|
||||
];
|
||||
] ++ (with pkgs.lomiri; [
|
||||
lomiri-indicator-network
|
||||
]);
|
||||
};
|
||||
|
||||
# Services needed by some indicators
|
||||
# Setup needed by some indicators
|
||||
|
||||
services.accounts-daemon.enable = true; # messages
|
||||
|
||||
# Lomiri-ish setup for Lomiri indicators
|
||||
# TODO move into a Lomiri module, once the package set is far enough for the DE to start
|
||||
|
||||
networking.networkmanager.enable = true; # lomiri-network-indicator
|
||||
# TODO potentially urfkill for lomiri-network-indicator?
|
||||
};
|
||||
|
||||
# TODO session indicator starts up in a semi-broken state, but works fine after a restart. maybe being started before graphical session is truly up & ready?
|
||||
testScript = { nodes, ... }: let
|
||||
runCommandPerIndicatorService = command: lib.strings.concatMapStringsSep "\n" command nodes.machine.systemd.user.targets."ayatana-indicators".wants;
|
||||
runCommandOverServiceList = list: command:
|
||||
lib.strings.concatMapStringsSep "\n" command list;
|
||||
|
||||
runCommandOverAyatanaIndicators = runCommandOverServiceList
|
||||
(builtins.filter
|
||||
(service: !(lib.strings.hasPrefix "lomiri" service || lib.strings.hasPrefix "telephony-service" service))
|
||||
nodes.machine.systemd.user.targets."ayatana-indicators".wants);
|
||||
|
||||
runCommandOverAllIndicators = runCommandOverServiceList
|
||||
nodes.machine.systemd.user.targets."ayatana-indicators".wants;
|
||||
in ''
|
||||
start_all()
|
||||
machine.wait_for_x()
|
||||
@ -50,7 +68,7 @@ in {
|
||||
machine.sleep(10)
|
||||
|
||||
# Now check if all indicators were brought up successfully, and kill them for later
|
||||
'' + (runCommandPerIndicatorService (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
|
||||
'' + (runCommandOverAyatanaIndicators (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
|
||||
machine.succeed("pgrep -f ${serviceExec}")
|
||||
machine.succeed("pkill -f ${serviceExec}")
|
||||
'')) + ''
|
||||
@ -65,7 +83,7 @@ in {
|
||||
machine.sleep(10)
|
||||
|
||||
# Now check if all indicator services were brought up successfully
|
||||
'' + runCommandPerIndicatorService (service: ''
|
||||
'' + runCommandOverAllIndicators (service: ''
|
||||
machine.wait_for_unit("${service}", "${user}")
|
||||
'');
|
||||
})
|
||||
|
@ -120,10 +120,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
|
||||
''
|
||||
start_all()
|
||||
|
||||
client.wait_for_unit("network-online.target")
|
||||
local_router.wait_for_unit("network-online.target")
|
||||
remote_router.wait_for_unit("network-online.target")
|
||||
|
||||
local_router.wait_for_unit("babeld.service")
|
||||
remote_router.wait_for_unit("babeld.service")
|
||||
|
||||
|
@ -115,6 +115,7 @@ in
|
||||
start_all()
|
||||
|
||||
# Wait for network and miniupnpd.
|
||||
router.systemctl("start network-online.target")
|
||||
router.wait_for_unit("network-online.target")
|
||||
router.wait_for_unit("miniupnpd")
|
||||
|
||||
@ -129,6 +130,7 @@ in
|
||||
tracker.succeed("chmod 644 /tmp/test.torrent")
|
||||
|
||||
# Start the tracker. !!! use a less crappy tracker
|
||||
tracker.systemctl("start network-online.target")
|
||||
tracker.wait_for_unit("network-online.target")
|
||||
tracker.wait_for_unit("opentracker.service")
|
||||
tracker.wait_for_open_port(6969)
|
||||
@ -140,6 +142,7 @@ in
|
||||
|
||||
# Now we should be able to download from the client behind the NAT.
|
||||
tracker.wait_for_unit("httpd")
|
||||
client1.systemctl("start network-online.target")
|
||||
client1.wait_for_unit("network-online.target")
|
||||
client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &")
|
||||
client1.wait_for_file("${download-dir}/test.tar.bz2")
|
||||
@ -152,6 +155,7 @@ in
|
||||
|
||||
# Now download from the second client. This can only succeed if
|
||||
# the first client created a NAT hole in the router.
|
||||
client2.systemctl("start network-online.target")
|
||||
client2.wait_for_unit("network-online.target")
|
||||
client2.succeed(
|
||||
"transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &"
|
||||
|
@ -71,6 +71,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
gitrepo.wait_for_unit("multi-user.target")
|
||||
|
||||
with subtest("Repo is accessible via git daemon"):
|
||||
bbmaster.systemctl("start network-online.target")
|
||||
bbmaster.wait_for_unit("network-online.target")
|
||||
bbmaster.succeed("rm -rfv /tmp/fakerepo")
|
||||
bbmaster.succeed("git clone git://gitrepo/fakerepo /tmp/fakerepo")
|
||||
@ -78,6 +79,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
with subtest("Master service and worker successfully connect"):
|
||||
bbmaster.wait_for_unit("buildbot-master.service")
|
||||
bbmaster.wait_until_succeeds("curl --fail -s --head http://bbmaster:8010")
|
||||
bbworker.systemctl("start network-online.target")
|
||||
bbworker.wait_for_unit("network-online.target")
|
||||
bbworker.succeed("nc -z bbmaster 8010")
|
||||
bbworker.succeed("nc -z bbmaster 9989")
|
||||
|
@ -56,6 +56,8 @@ import ./make-test-python.nix (
|
||||
|
||||
with subtest("Wait for CoreRAD and network ready"):
|
||||
# Ensure networking is online and CoreRAD is ready.
|
||||
router.systemctl("start network-online.target")
|
||||
client.systemctl("start network-online.target")
|
||||
router.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
router.wait_for_unit("corerad.service")
|
||||
|
@ -144,6 +144,8 @@ in {
|
||||
start_all()
|
||||
|
||||
with subtest("Wait for network"):
|
||||
web.systemctl("start network-online.target")
|
||||
curl.systemctl("start network-online.target")
|
||||
web.wait_for_unit("network-online.target")
|
||||
curl.wait_for_unit("network-online.target")
|
||||
|
||||
|
@ -55,6 +55,8 @@ import ./make-test-python.nix ({ pkgs, ...} : {
|
||||
''
|
||||
start_all()
|
||||
|
||||
client.systemctl("start network-online.target")
|
||||
server.systemctl("start network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
server.wait_for_unit("ferm.service")
|
||||
|
@ -59,6 +59,9 @@ in {
|
||||
with subtest("git daemon starts"):
|
||||
server.wait_for_unit("git-daemon.service")
|
||||
|
||||
|
||||
server.systemctl("start network-online.target")
|
||||
client.systemctl("start network-online.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user