diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 4533f26214f5..f07ad90dd544 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -43,6 +43,8 @@ - [Omnom](https://github.com/asciimoo/omnom), a webpage bookmarking and snapshotting service. Available as [services.omnom](options.html#opt-services.omnom.enable). +- [Zenoh](https://zenoh.io/), a pub/sub/query protocol with low overhead. The Zenoh router daemon is available as [services.zenohd](options.html#opt-services.zenohd.enable) + - [MaryTTS](https://github.com/marytts/marytts), an open-source, multilingual text-to-speech synthesis system written in pure Java. Available as [services.marytts](options.html#opt-services.marytts). - [networking.modemmanager](options.html#opt-networking.modemmanager) has been split out of [networking.networkmanager](options.html#opt-networking.networkmanager). NetworkManager still enables ModemManager by default, but options exist now to run NetworkManager without ModemManager. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 92e8db5ee8e1..b44240e0d87d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1315,6 +1315,7 @@ ./services/networking/yggdrasil.nix ./services/networking/zapret.nix ./services/networking/zerobin.nix + ./services/networking/zenohd.nix ./services/networking/zeronet.nix ./services/networking/zerotierone.nix ./services/networking/zeronsd.nix diff --git a/nixos/modules/services/networking/zenohd.nix b/nixos/modules/services/networking/zenohd.nix new file mode 100644 index 000000000000..70eceab48792 --- /dev/null +++ b/nixos/modules/services/networking/zenohd.nix @@ -0,0 +1,136 @@ +{ + lib, + config, + pkgs, + ... +}: + +let + inherit (lib) + types + mkDefault + mkOption + ; + + json = pkgs.formats.json { }; + + cfg = config.services.zenohd; + +in +{ + options = { + services.zenohd = { + enable = lib.mkEnableOption "Zenoh daemon."; + + package = mkOption { + description = "The zenoh package to use."; + type = types.package; + default = pkgs.zenoh; + defaultText = "pkgs.zenoh"; + }; + + settings = mkOption { + description = '' + Config options for `zenoh.json5` configuration file. + + See + for more information. + ''; + default = { }; + type = types.submodule { + freeformType = json.type; + }; + }; + + plugins = mkOption { + description = "Plugin packages to add to zenohd search paths."; + type = with types; listOf package; + default = [ ]; + example = lib.literalExpression '' + [ pkgs.zenoh-plugin-mqtt ] + ''; + }; + + backends = mkOption { + description = "Storage backend packages to add to zenohd search paths."; + type = with types; listOf package; + default = [ ]; + example = lib.literalExpression '' + [ pkgs.zenoh-backend-rocksdb ] + ''; + }; + + home = mkOption { + description = "Base directory for zenohd related files defined via ZENOH_HOME."; + type = types.str; + default = "/var/lib/zenoh"; + }; + + env = mkOption { + description = '' + Set environment variables consumed by zenohd and its plugins. + ''; + type = with types; attrsOf str; + default = { }; + }; + + extraOptions = mkOption { + description = "Extra command line options for zenohd."; + type = with types; listOf str; + default = [ ]; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.zenohd = + let + cfgFile = json.generate "zenohd.json" cfg.settings; + + in + { + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + environment = cfg.env; + + serviceConfig = { + Type = "simple"; + User = "zenohd"; + Group = "zenohd"; + ExecStart = + "${lib.getExe cfg.package} -c ${cfgFile} " + (lib.concatStringsSep " " cfg.extraOptions); + }; + }; + + users = { + users.zenohd = { + description = "Zenoh daemon user"; + group = "zenohd"; + isSystemUser = true; + }; + + groups.zenohd = { }; + }; + + services.zenohd = { + env.ZENOH_HOME = cfg.home; + + settings = { + plugins_loading = { + enabled = mkDefault true; + search_dirs = mkDefault ( + (map (x: "${lib.getLib x}/lib") cfg.plugins) ++ [ "${lib.getLib cfg.package}/lib" ] + ); # needed for internal plugins + }; + + plugins.storage_manager.backend_search_dirs = mkDefault ( + map (x: "${lib.getLib x}/lib") cfg.backends + ); + }; + }; + + systemd.tmpfiles.rules = [ "d ${cfg.home} 750 zenohd zenohd -" ]; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 2952c67d19c2..93fafe376a95 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1186,6 +1186,7 @@ in { yggdrasil = handleTest ./yggdrasil.nix {}; your_spotify = handleTest ./your_spotify.nix {}; zammad = handleTest ./zammad.nix {}; + zenohd = handleTest ./zenohd.nix {}; zeronet-conservancy = handleTest ./zeronet-conservancy.nix {}; zfs = handleTest ./zfs.nix {}; zigbee2mqtt = handleTest ./zigbee2mqtt.nix {}; diff --git a/nixos/tests/zenohd.nix b/nixos/tests/zenohd.nix new file mode 100644 index 000000000000..7d99460d6ade --- /dev/null +++ b/nixos/tests/zenohd.nix @@ -0,0 +1,94 @@ +import ./make-test-python.nix ( + { pkgs, lib, ... }: + + { + name = "zenohd"; + meta.maintainers = [ lib.maintainers.markuskowa ]; + + nodes = { + router = + { + pkgs, + lib, + config, + ... + }: + { + networking.firewall.allowedTCPPorts = [ + 7447 # zenohd default port + config.services.zenohd.settings.plugins.mqtt.port + config.services.zenohd.settings.plugins.webserver.http_port + ]; + + services.zenohd = { + enable = true; + + plugins = with pkgs; [ + zenoh-plugin-mqtt + zenoh-plugin-webserver + ]; + + backends = with pkgs; [ + zenoh-backend-filesystem + zenoh-backend-rocksdb + ]; + + settings = { + plugins = { + mqtt = { + port = 1883; + allow = ".*"; + }; + webserver.http_port = 8000; + storage_manager = { + volumes = { + fs = { }; + rocksdb = { }; + }; + storages = { + mem = { + key_expr = "mem/**"; + volume = "memory"; + }; + fs = { + key_expr = "fs/**"; + volume = { + id = "fs"; + dir = "zenoh-fs"; + strip_prefix = "fs"; + }; + }; + rocksdb = { + key_expr = "rocksdb/**"; + volume = { + id = "rocksdb"; + dir = "zenoh-rocksdb"; + strip_prefix = "rocksdb"; + create_db = true; + }; + }; + }; + }; + }; + }; + }; + }; + + client = { + environment.systemPackages = [ + pkgs.mosquitto + ]; + }; + }; + + testScript = '' + start_all() + router.wait_for_unit("zenohd.service") + client.wait_for_unit("multi-user.target") + + for be in ["fs", "rocksdb", "mem" ]: + client.succeed(f"mosquitto_pub -h router -t {be}/test -m hello") + client.succeed(f"curl router:8000/{be}/test | grep hello") + ''; + } +)