From cba3d0d236d6e121e88fa14056489ac080d9a4fe Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Sun, 3 Mar 2024 18:07:00 +0000 Subject: [PATCH 1/4] homepage-dashboard: patch to enable control of log targets This piece of software is generally used (and documented upstream) in containers. It is common practice for such applications to log both to stdout, and to a file which can be volume-mounted in the container. Because the intention here is to start with systemd, it makes less sense to have both, so this added patch stops the application from trying to create a log directory alongside the config directory. --- pkgs/servers/homepage-dashboard/default.nix | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkgs/servers/homepage-dashboard/default.nix b/pkgs/servers/homepage-dashboard/default.nix index 7a28803df611..6f0a94500ef0 100644 --- a/pkgs/servers/homepage-dashboard/default.nix +++ b/pkgs/servers/homepage-dashboard/default.nix @@ -39,6 +39,20 @@ buildNpmPackage rec { npmDepsHash = "sha256-u15lDdXnV3xlXAC9WQQKLIeV/AgtRM1sFNsacw3j6kU="; + # This project is primarily designed to be consumed through Docker. + # By default it logs to stdout, and also to a directory. This makes + # little sense here where all the logs will be collated in the + # systemd journal anyway, so the patch removes the file logging. + # This patch has been suggested upstream, but the contribution won't + # be accepted until it gets at least 10 upvotes, per their policy: + # https://github.com/gethomepage/homepage/discussions/3067 + patches = [ + (fetchpatch { + url = "https://github.com/gethomepage/homepage/commit/3be28a2c8b68f2404e4083e7f32eebbccdc4d293.patch"; + hash = "sha256-5fUOXiHBZ4gdPeOHe1NIaBLaHJTDImsRjSwtueQOEXY="; + }) + ]; + preBuild = '' mkdir -p config ''; From c0330351a06ffebc70e4bbcfe9bad43449aab4b7 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Mon, 26 Feb 2024 12:00:01 +0000 Subject: [PATCH 2/4] nixos/homepage-dashboard: support structured config --- .../services/misc/homepage-dashboard.nix | 226 ++++++++++++++++-- 1 file changed, 207 insertions(+), 19 deletions(-) diff --git a/nixos/modules/services/misc/homepage-dashboard.nix b/nixos/modules/services/misc/homepage-dashboard.nix index 07a09e2b6bbf..02f1378cb0d5 100644 --- a/nixos/modules/services/misc/homepage-dashboard.nix +++ b/nixos/modules/services/misc/homepage-dashboard.nix @@ -6,6 +6,8 @@ let cfg = config.services.homepage-dashboard; + # Define the settings format used for this program + settingsFormat = pkgs.formats.yaml { }; in { options = { @@ -25,31 +27,217 @@ in default = 8082; description = lib.mdDoc "Port for Homepage to bind to."; }; + + environmentFile = lib.mkOption { + type = lib.types.str; + description = '' + The path to an environment file that contains environment variables to pass + to the homepage-dashboard service, for the purpose of passing secrets to + the service. + + See the upstream documentation: + + https://gethomepage.dev/latest/installation/docker/#using-environment-secrets + ''; + default = ""; + }; + + customCSS = lib.mkOption { + type = lib.types.lines; + description = lib.mdDoc '' + Custom CSS for styling Homepage. + + See https://gethomepage.dev/latest/configs/custom-css-js/. + ''; + default = ""; + }; + + customJS = lib.mkOption { + type = lib.types.lines; + description = lib.mdDoc '' + Custom Javascript for Homepage. + + See https://gethomepage.dev/latest/configs/custom-css-js/. + ''; + default = ""; + }; + + bookmarks = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage bookmarks configuration. + + See https://gethomepage.dev/latest/configs/bookmarks/. + ''; + # Defaults: https://github.com/gethomepage/homepage/blob/main/src/skeleton/bookmarks.yaml + example = [ + { + Developer = [ + { Github = [{ abbr = "GH"; href = "https://github.com/"; }]; } + ]; + } + { + Entertainment = [ + { YouTube = [{ abbr = "YT"; href = "https://youtube.com/"; }]; } + ]; + } + ]; + default = [ ]; + }; + + services = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage services configuration. + + See https://gethomepage.dev/latest/configs/services/. + ''; + # Defaults: https://github.com/gethomepage/homepage/blob/main/src/skeleton/services.yaml + example = [ + { + "My First Group" = [ + { + "My First Service" = { + href = "http://localhost/"; + description = "Homepage is awesome"; + }; + } + ]; + } + { + "My Second Group" = [ + { + "My Second Service" = { + href = "http://localhost/"; + description = "Homepage is the best"; + }; + } + ]; + } + ]; + default = [ ]; + }; + + widgets = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage widgets configuration. + + See https://gethomepage.dev/latest/configs/service-widgets/. + ''; + # Defaults: https://github.com/gethomepage/homepage/blob/main/src/skeleton/widgets.yaml + example = [ + { + resources = { + cpu = true; + memory = true; + disk = "/"; + }; + } + { + search = { + provider = "duckduckgo"; + target = "_blank"; + }; + } + ]; + default = [ ]; + }; + + kubernetes = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage kubernetes configuration. + + See https://gethomepage.dev/latest/configs/kubernetes/. + ''; + default = { }; + }; + + docker = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage docker configuration. + + See https://gethomepage.dev/latest/configs/docker/. + ''; + default = { }; + }; + + settings = lib.mkOption { + inherit (settingsFormat) type; + description = lib.mdDoc '' + Homepage settings. + + See https://gethomepage.dev/latest/configs/settings/. + ''; + # Defaults: https://github.com/gethomepage/homepage/blob/main/src/skeleton/settings.yaml + default = { }; + }; }; }; - config = lib.mkIf cfg.enable { - systemd.services.homepage-dashboard = { - description = "Homepage Dashboard"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; + config = + let + # If homepage-dashboard is enabled, but none of the configuration values have been updated, + # then default to "unmanaged" configuration which is manually updated in + # var/lib/homepage-dashboard. This is to maintain backwards compatibility, and should be + # deprecated in a future release. + managedConfig = !( + cfg.bookmarks == [ ] && + cfg.customCSS == "" && + cfg.customJS == "" && + cfg.docker == { } && + cfg.kubernetes == { } && + cfg.services == [ ] && + cfg.settings == { } && + cfg.widgets == [ ] + ); - environment = { - HOMEPAGE_CONFIG_DIR = "/var/lib/homepage-dashboard"; - PORT = "${toString cfg.listenPort}"; + configDir = if managedConfig then "/etc/homepage-dashboard" else "/var/lib/homepage-dashboard"; + + msg = "using unmanaged configuration for homepage-dashboard is deprecated and will be removed" + + " in 24.05. please see the NixOS documentation for `services.homepage-dashboard' and add" + + " your bookmarks, services, widgets, and other configuration using the options provided."; + in + lib.mkIf cfg.enable { + warnings = lib.optional (!managedConfig) msg; + + environment.etc = lib.mkIf managedConfig { + "homepage-dashboard/custom.css".text = cfg.customCSS; + "homepage-dashboard/custom.js".text = cfg.customJS; + + "homepage-dashboard/bookmarks.yaml".source = settingsFormat.generate "bookmarks.yaml" cfg.bookmarks; + "homepage-dashboard/docker.yaml".source = settingsFormat.generate "docker.yaml" cfg.docker; + "homepage-dashboard/kubernetes.yaml".source = settingsFormat.generate "kubernetes.yaml" cfg.kubernetes; + "homepage-dashboard/services.yaml".source = settingsFormat.generate "services.yaml" cfg.services; + "homepage-dashboard/settings.yaml".source = settingsFormat.generate "settings.yaml" cfg.settings; + "homepage-dashboard/widgets.yaml".source = settingsFormat.generate "widgets.yaml" cfg.widgets; }; - serviceConfig = { - Type = "simple"; - DynamicUser = true; - StateDirectory = "homepage-dashboard"; - ExecStart = "${lib.getExe cfg.package}"; - Restart = "on-failure"; + systemd.services.homepage-dashboard = { + description = "Homepage Dashboard"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + HOMEPAGE_CONFIG_DIR = configDir; + PORT = toString cfg.listenPort; + LOG_TARGETS = lib.mkIf managedConfig "stdout"; + }; + + serviceConfig = { + Type = "simple"; + DynamicUser = true; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; + StateDirectory = lib.mkIf (!managedConfig) "homepage-dashboard"; + ExecStart = lib.getExe cfg.package; + Restart = "on-failure"; + }; + }; + + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.listenPort ]; }; }; - - networking.firewall = lib.mkIf cfg.openFirewall { - allowedTCPPorts = [ cfg.listenPort ]; - }; - }; } From 183bc82cca1e3175cc3bfda91fb2525bb3b88c05 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Mon, 26 Feb 2024 18:03:28 +0000 Subject: [PATCH 3/4] nixos/homepage-dashboard: add breaking change notice to release notes --- nixos/doc/manual/release-notes/rl-2405.section.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index b5973c19a2c4..08cba1790ca2 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -134,6 +134,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `paperless`' `services.paperless.extraConfig` setting has been removed and converted to the freeform type and option named `services.paperless.settings`. +- `services.homepage-dashboard` now takes it's configuration using native Nix expressions, rather than dumping templated configurations into `/var/lib/homepage-dashboard` where they were previously managed manually. There are now new options which allow the configuration of bookmarks, services, widgets and custom CSS/JS natively in Nix. + - The legacy and long deprecated systemd target `network-interfaces.target` has been removed. Use `network.target` instead. - `services.frp.settings` now generates the frp configuration file in TOML format as [recommended by upstream](https://github.com/fatedier/frp#configuration-files), instead of the legacy INI format. This has also introduced other changes in the configuration file structure and options. From 0b39e86cbc509bbe7d6e0a5c10f4860e68483e53 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Sun, 3 Mar 2024 18:07:28 +0000 Subject: [PATCH 4/4] nixosTests.homepage-dashboard: test managed and unmanaged configs --- nixos/tests/homepage-dashboard.nix | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/nixos/tests/homepage-dashboard.nix b/nixos/tests/homepage-dashboard.nix index 56e077f5ff6d..dd36473e8ac0 100644 --- a/nixos/tests/homepage-dashboard.nix +++ b/nixos/tests/homepage-dashboard.nix @@ -2,13 +2,35 @@ import ./make-test-python.nix ({ lib, ... }: { name = "homepage-dashboard"; meta.maintainers = with lib.maintainers; [ jnsgruk ]; - nodes.machine = { pkgs, ... }: { + nodes.unmanaged_conf = { pkgs, ... }: { services.homepage-dashboard.enable = true; }; + nodes.managed_conf = { pkgs, ... }: { + services.homepage-dashboard = { + enable = true; + settings.title = "custom"; + }; + }; + testScript = '' - machine.wait_for_unit("homepage-dashboard.service") - machine.wait_for_open_port(8082) - machine.succeed("curl --fail http://localhost:8082/") + # Ensure the services are started on unmanaged machine + unmanaged_conf.wait_for_unit("homepage-dashboard.service") + unmanaged_conf.wait_for_open_port(8082) + unmanaged_conf.succeed("curl --fail http://localhost:8082/") + + # Ensure that /etc/homepage-dashboard doesn't exist, and boilerplate + # configs are copied into place. + unmanaged_conf.fail("test -d /etc/homepage-dashboard") + unmanaged_conf.succeed("test -f /var/lib/private/homepage-dashboard/settings.yaml") + + # Ensure the services are started on managed machine + managed_conf.wait_for_unit("homepage-dashboard.service") + managed_conf.wait_for_open_port(8082) + managed_conf.succeed("curl --fail http://localhost:8082/") + + # Ensure /etc/homepage-dashboard is created and unmanaged conf location isn't. + managed_conf.succeed("test -d /etc/homepage-dashboard") + managed_conf.fail("test -f /var/lib/private/homepage-dashboard/settings.yaml") ''; })