292 lines
11 KiB
Diff
292 lines
11 KiB
Diff
diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md
|
|
index 10645d55e8389..e4ffb75742580 100644
|
|
--- a/nixos/doc/manual/release-notes/rl-2505.section.md
|
|
+++ b/nixos/doc/manual/release-notes/rl-2505.section.md
|
|
@@ -40,6 +40,10 @@
|
|
add `vimPlugins.notmuch-vim` to your (Neo)vim configuration if you want the
|
|
vim plugin.
|
|
|
|
+- The `octoprint` service has gained an `enableRaspberryPi` option, which will
|
|
+ be disabled for state versions following 25.05. Users running on Raspberry Pi
|
|
+ should enable the option to restore full functionality.
|
|
+
|
|
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
|
|
|
## Other Notable Changes {#sec-release-25.05-notable-changes}
|
|
diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix
|
|
index d8e4c9c302b38..6ab48ee10e3c7 100644
|
|
--- a/nixos/modules/services/misc/octoprint.nix
|
|
+++ b/nixos/modules/services/misc/octoprint.nix
|
|
@@ -1,17 +1,27 @@
|
|
-{ config, lib, pkgs, ... }:
|
|
+{
|
|
+ config,
|
|
+ lib,
|
|
+ pkgs,
|
|
+ ...
|
|
+}:
|
|
let
|
|
|
|
- cfg = config.services.octoprint;
|
|
+ inherit (lib)
|
|
+ literalExpression
|
|
+ mkDefault
|
|
+ mkEnableOption
|
|
+ mkOption
|
|
+ mkRenamedOptionModule
|
|
+ optional
|
|
+ types
|
|
+ versionOlder
|
|
+ ;
|
|
|
|
- baseConfig = {
|
|
- plugins.curalegacy.cura_engine = "${pkgs.curaengine_stable}/bin/CuraEngine";
|
|
- server.port = cfg.port;
|
|
- webcam.ffmpeg = "${pkgs.ffmpeg.bin}/bin/ffmpeg";
|
|
- } // lib.optionalAttrs (cfg.host != null) {server.host = cfg.host;};
|
|
+ cfg = config.services.octoprint;
|
|
|
|
- fullConfig = lib.recursiveUpdate cfg.extraConfig baseConfig;
|
|
+ formatType = pkgs.formats.json { };
|
|
|
|
- cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON fullConfig);
|
|
+ configFile = formatType.generate "octoprint-config.yaml" cfg.settings;
|
|
|
|
pluginsEnv = package.python.withPackages (ps: [ ps.octoprint ] ++ (cfg.plugins ps));
|
|
|
|
@@ -67,18 +77,32 @@ in
|
|
description = "State directory of the daemon.";
|
|
};
|
|
|
|
- plugins = lib.mkOption {
|
|
- type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
|
- default = plugins: [ ];
|
|
- defaultText = lib.literalExpression "plugins: []";
|
|
- example = lib.literalExpression "plugins: with plugins; [ themeify stlviewer ]";
|
|
+ plugins = mkOption {
|
|
+ type = types.functionTo (types.listOf types.package);
|
|
+ default = _plugins: [ ];
|
|
+ defaultText = literalExpression "plugins: []";
|
|
+ example = literalExpression "plugins: with plugins; [ themeify stlviewer ]";
|
|
description = "Additional plugins to be used. Available plugins are passed through the plugins input.";
|
|
};
|
|
|
|
- extraConfig = lib.mkOption {
|
|
- type = lib.types.attrs;
|
|
+ settings = mkOption {
|
|
default = { };
|
|
- description = "Extra options which are added to OctoPrint's YAML configuration file.";
|
|
+ description = ''
|
|
+ The octoprint settings, for definitions see the upstream [documentation](https://docs.octoprint.org).
|
|
+ Will override any existing settings.
|
|
+ '';
|
|
+ type = types.submodule {
|
|
+ freeformType = formatType.type;
|
|
+ config = {
|
|
+ plugins.curalegacy.cura_engine = mkDefault "${pkgs.curaengine_stable}/bin/CuraEngine";
|
|
+ server.host = cfg.host;
|
|
+ server.port = cfg.port;
|
|
+ webcam.ffmpeg = mkDefault "${pkgs.ffmpeg.bin}/bin/ffmpeg";
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ enableRaspberryPi = mkEnableOption "RaspberryPi specific hardware access rules" // {
|
|
+ default = versionOlder config.system.stateVersion "25.05";
|
|
};
|
|
|
|
};
|
|
@@ -86,6 +110,20 @@ in
|
|
};
|
|
|
|
##### implementation
|
|
+ imports = [
|
|
+ (mkRenamedOptionModule
|
|
+ [
|
|
+ "services"
|
|
+ "octoprint"
|
|
+ "extraConfig"
|
|
+ ]
|
|
+ [
|
|
+ "services"
|
|
+ "octoprint"
|
|
+ "settings"
|
|
+ ]
|
|
+ )
|
|
+ ];
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
|
|
@@ -100,12 +138,13 @@ in
|
|
octoprint.gid = config.ids.gids.octoprint;
|
|
};
|
|
|
|
- systemd.tmpfiles.rules = [
|
|
- "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
|
|
- # this will allow octoprint access to raspberry specific hardware to check for throttling
|
|
- # read-only will not work: "VCHI initialization failed" error
|
|
- "a /dev/vchiq - - - - u:octoprint:rw"
|
|
- ];
|
|
+ systemd.tmpfiles.rules =
|
|
+ [ "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -" ]
|
|
+ ++ optional cfg.enableRaspberryPi
|
|
+ # this will allow octoprint access to raspberry specific hardware to check for throttling
|
|
+ # read-only will not work: "VCHI initialization failed" error
|
|
+ # FIXME: this should probably be a udev rule
|
|
+ "a /dev/vchiq - - - - u:octoprint:rw";
|
|
|
|
systemd.services.octoprint = {
|
|
description = "OctoPrint, web interface for 3D printers";
|
|
@@ -115,10 +154,10 @@ in
|
|
|
|
preStart = ''
|
|
if [ -e "${cfg.stateDir}/config.yaml" ]; then
|
|
- ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${cfgUpdate}" > "${cfg.stateDir}/config.yaml.tmp"
|
|
+ ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${configFile}" > "${cfg.stateDir}/config.yaml.tmp"
|
|
mv "${cfg.stateDir}/config.yaml.tmp" "${cfg.stateDir}/config.yaml"
|
|
else
|
|
- cp "${cfgUpdate}" "${cfg.stateDir}/config.yaml"
|
|
+ cp "${configFile}" "${cfg.stateDir}/config.yaml"
|
|
chmod 600 "${cfg.stateDir}/config.yaml"
|
|
fi
|
|
'';
|
|
@@ -127,12 +166,42 @@ in
|
|
ExecStart = "${pluginsEnv}/bin/octoprint serve -b ${cfg.stateDir}";
|
|
User = cfg.user;
|
|
Group = cfg.group;
|
|
- SupplementaryGroups = [
|
|
- "dialout"
|
|
+ SupplementaryGroups = [ "dialout" ];
|
|
+
|
|
+ # Hardening
|
|
+ CapabilityBoundingSet = "";
|
|
+ LockPersonality = true;
|
|
+ MemoryDenyWriteExecute = true;
|
|
+ PrivateUsers = true;
|
|
+ ProtectClock = true;
|
|
+ ProtectControlGroups = true;
|
|
+ ProtectHome = true;
|
|
+ ProtectHostname = true;
|
|
+ ProtectKernelLogs = true;
|
|
+ ProtectKernelModules = true;
|
|
+ ProtectKernelTunables = true;
|
|
+ ProtectProc = "invisible";
|
|
+ ProcSubset = "pid";
|
|
+ ProtectSystem = "strict";
|
|
+ RestrictAddressFamilies = [
|
|
+ "AF_INET"
|
|
+ "AF_INET6"
|
|
+ "AF_NETLINK"
|
|
];
|
|
+ RestrictNamespaces = true;
|
|
+ RestrictRealtime = true;
|
|
+ SystemCallArchitectures = "native";
|
|
+ SystemCallFilter = [
|
|
+ "@system-service"
|
|
+ "@pkey"
|
|
+ ];
|
|
+ ReadWritePaths = [ cfg.stateDir ];
|
|
+ UMask = "0077";
|
|
+
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
|
|
};
|
|
+ meta.maintainers = with lib.maintainers; [ patrickdag ];
|
|
}
|
|
diff --git a/nixos/tests/octoprint.nix b/nixos/tests/octoprint.nix
|
|
index 15a2d677d4cf8..dc60b10813311 100644
|
|
--- a/nixos/tests/octoprint.nix
|
|
+++ b/nixos/tests/octoprint.nix
|
|
@@ -11,7 +11,7 @@ in
|
|
environment.systemPackages = with pkgs; [ jq ];
|
|
services.octoprint = {
|
|
enable = true;
|
|
- extraConfig = {
|
|
+ settings = {
|
|
server = {
|
|
firstRun = false;
|
|
};
|
|
@@ -50,11 +50,18 @@ in
|
|
# used to fail early, in case octoprint first starts and then crashes
|
|
with octoprint_running: # type: ignore[union-attr]
|
|
with subtest("Check for web interface"):
|
|
- machine.wait_until_succeeds("curl -s localhost:5000")
|
|
+ machine.wait_until_succeeds("curl -s -4 localhost:5000")
|
|
+ machine.wait_until_succeeds("curl -s -6 localhost:5000")
|
|
|
|
- with subtest("Check API"):
|
|
- version = json.loads(machine.succeed(curl_cmd + "localhost:5000/api/version"))
|
|
- server = json.loads(machine.succeed(curl_cmd + "localhost:5000/api/server"))
|
|
+ with subtest("Check API IPv4"):
|
|
+ version = json.loads(machine.succeed(curl_cmd + "-4 localhost:5000/api/version"))
|
|
+ server = json.loads(machine.succeed(curl_cmd + "-4 localhost:5000/api/server"))
|
|
+ assert version["server"] == str("${pkgs.octoprint.version}")
|
|
+ assert server["safemode"] == None
|
|
+
|
|
+ with subtest("Check API IPv6"):
|
|
+ version = json.loads(machine.succeed(curl_cmd + "-6 localhost:5000/api/version"))
|
|
+ server = json.loads(machine.succeed(curl_cmd + "-6 localhost:5000/api/server"))
|
|
assert version["server"] == str("${pkgs.octoprint.version}")
|
|
assert server["safemode"] == None
|
|
'';
|
|
diff --git a/pkgs/by-name/oc/octoprint/ffmpeg-path.patch b/pkgs/by-name/oc/octoprint/ffmpeg-path.patch
|
|
deleted file mode 100644
|
|
index 2e7c7dbe06428..0000000000000
|
|
--- a/pkgs/by-name/oc/octoprint/ffmpeg-path.patch
|
|
+++ /dev/null
|
|
@@ -1,22 +0,0 @@
|
|
-diff --git a/src/octoprint/server/api/settings.py b/src/octoprint/server/api/settings.py
|
|
-index c3e6cea10..ced2f8fa0 100644
|
|
---- a/src/octoprint/server/api/settings.py
|
|
-+++ b/src/octoprint/server/api/settings.py
|
|
-@@ -130,7 +130,7 @@ data["webcam"] = {
|
|
- "webcamEnabled": s.getBoolean(["webcam", "webcamEnabled"]),
|
|
- "snapshotTimeout": s.getInt(["webcam", "snapshotTimeout"]),
|
|
- "timelapseEnabled": s.getBoolean(["webcam", "timelapseEnabled"]),
|
|
-- "ffmpegPath": s.get(["webcam", "ffmpeg"]),
|
|
-+ "ffmpegPath": "@ffmpeg@",
|
|
- "ffmpegCommandline": s.get(["webcam", "ffmpegCommandline"]),
|
|
- "bitrate": s.get(["webcam", "bitrate"]),
|
|
- "ffmpegThreads": s.get(["webcam", "ffmpegThreads"]),
|
|
-@@ -548,8 +548,6 @@ def _saveSettings(data):
|
|
- ["webcam", "snapshotSslValidation"],
|
|
- data["webcam"]["snapshotSslValidation"],
|
|
- )
|
|
-- if "ffmpegPath" in data["webcam"]:
|
|
-- s.set(["webcam", "ffmpeg"], data["webcam"]["ffmpegPath"])
|
|
- if "ffmpegCommandline" in data["webcam"]:
|
|
- commandline = data["webcam"]["ffmpegCommandline"]
|
|
- if not all(
|
|
diff --git a/pkgs/by-name/oc/octoprint/package.nix b/pkgs/by-name/oc/octoprint/package.nix
|
|
index a4b437ac6d1c7..3042f7d6dd643 100644
|
|
--- a/pkgs/by-name/oc/octoprint/package.nix
|
|
+++ b/pkgs/by-name/oc/octoprint/package.nix
|
|
@@ -1,5 +1,4 @@
|
|
{
|
|
- pkgs,
|
|
stdenv,
|
|
callPackage,
|
|
lib,
|
|
@@ -197,12 +196,6 @@ let
|
|
src = ./pip-path.patch;
|
|
pip = "${self.pip}/bin/pip";
|
|
})
|
|
-
|
|
- # hardcore path to ffmpeg and hide related settings
|
|
- (substituteAll {
|
|
- src = ./ffmpeg-path.patch;
|
|
- ffmpeg = "${pkgs.ffmpeg}/bin/ffmpeg";
|
|
- })
|
|
];
|
|
|
|
postPatch =
|
|
@@ -266,6 +259,7 @@ let
|
|
gebner
|
|
WhittlesJr
|
|
gador
|
|
+ patrickdag
|
|
];
|
|
};
|
|
};
|