Loading nixos/modules/services/web-apps/glance.nix +56 −7 Original line number Diff line number Diff line Loading @@ -8,15 +8,27 @@ let cfg = config.services.glance; inherit (lib) catAttrs concatMapStrings getExe mkEnableOption mkPackageOption mkOption mkIf getExe mkOption mkPackageOption types ; inherit (builtins) concatLists isAttrs isList attrNames getAttr ; settingsFormat = pkgs.formats.yaml { }; settingsFile = settingsFormat.generate "glance.yaml" cfg.settings; mergedSettingsFile = "/run/glance/glance.yaml"; in { options.services.glance = { Loading Loading @@ -69,7 +81,9 @@ in { type = "calendar"; } { type = "weather"; location = "Nivelles, Belgium"; location = { _secret = "/var/lib/secrets/glance/location"; }; } ]; } Loading @@ -84,6 +98,13 @@ in Configuration written to a yaml file that is read by glance. See <https://github.com/glanceapp/glance/blob/main/docs/configuration.md> for more. Settings containing secret data should be set to an attribute set containing the attribute <literal>_secret</literal> - a string pointing to a file containing the value the option should be set to. See the example in `services.glance.settings.pages` at the weather widget with a location secret to get a better picture of this. ''; }; Loading @@ -102,13 +123,41 @@ in description = "Glance feed dashboard server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = [ pkgs.replace-secret ]; serviceConfig = { ExecStart = ExecStartPre = let glance-yaml = settingsFormat.generate "glance.yaml" cfg.settings; findSecrets = data: if isAttrs data then if data ? _secret then [ data ] else concatLists (map (attr: findSecrets (getAttr attr data)) (attrNames data)) else if isList data then concatLists (map findSecrets data) else [ ]; secretPaths = catAttrs "_secret" (findSecrets cfg.settings); mkSecretReplacement = secretPath: '' replace-secret ${ lib.escapeShellArgs [ "_secret: ${secretPath}" secretPath mergedSettingsFile ] } ''; secretReplacements = concatMapStrings mkSecretReplacement secretPaths; in "${getExe cfg.package} --config ${glance-yaml}"; # Use "+" to run as root because the secrets may not be accessible to glance "+" + pkgs.writeShellScript "glance-start-pre" '' install -m 600 -o $USER ${settingsFile} ${mergedSettingsFile} ${secretReplacements} ''; ExecStart = "${getExe cfg.package} --config ${mergedSettingsFile}"; WorkingDirectory = "/var/lib/glance"; StateDirectory = "glance"; RuntimeDirectory = "glance"; Loading nixos/tests/glance.nix +42 −6 Original line number Diff line number Diff line Loading @@ -5,19 +5,47 @@ nodes = { machine_default = { pkgs, ... }: { ... }: { services.glance = { enable = true; }; }; machine_custom_port = machine_configured = { pkgs, ... }: let # Do not use this in production. This will make the secret world-readable # in the Nix store secrets.glance-location.path = builtins.toString ( pkgs.writeText "location-secret" "Nivelles, Belgium" ); in { services.glance = { enable = true; settings.server.port = 5678; settings = { server.port = 5678; pages = [ { name = "Home"; columns = [ { size = "full"; widgets = [ { type = "calendar"; } { type = "weather"; location = { _secret = secrets.glance-location.path; }; } ]; } ]; } ]; }; }; }; }; Loading @@ -25,23 +53,31 @@ extraPythonPackages = p: with p; [ beautifulsoup4 pyyaml types-pyyaml types-beautifulsoup4 ]; testScript = '' from bs4 import BeautifulSoup import yaml machine_default.start() machine_default.wait_for_unit("glance.service") machine_default.wait_for_open_port(8080) machine_custom_port.start() machine_custom_port.wait_for_unit("glance.service") machine_custom_port.wait_for_open_port(5678) machine_configured.start() machine_configured.wait_for_unit("glance.service") machine_configured.wait_for_open_port(5678) soup = BeautifulSoup(machine_default.succeed("curl http://localhost:8080")) expected_version = "v${config.nodes.machine_default.services.glance.package.version}" assert any(a.text == expected_version for a in soup.select(".footer a")) yaml_contents = machine_configured.succeed("cat /run/glance/glance.yaml") yaml_parsed = yaml.load(yaml_contents, Loader=yaml.FullLoader) location = yaml_parsed["pages"][0]["columns"][0]["widgets"][1]["location"] assert location == "Nivelles, Belgium" ''; meta.maintainers = [ lib.maintainers.drupol ]; Loading Loading
nixos/modules/services/web-apps/glance.nix +56 −7 Original line number Diff line number Diff line Loading @@ -8,15 +8,27 @@ let cfg = config.services.glance; inherit (lib) catAttrs concatMapStrings getExe mkEnableOption mkPackageOption mkOption mkIf getExe mkOption mkPackageOption types ; inherit (builtins) concatLists isAttrs isList attrNames getAttr ; settingsFormat = pkgs.formats.yaml { }; settingsFile = settingsFormat.generate "glance.yaml" cfg.settings; mergedSettingsFile = "/run/glance/glance.yaml"; in { options.services.glance = { Loading Loading @@ -69,7 +81,9 @@ in { type = "calendar"; } { type = "weather"; location = "Nivelles, Belgium"; location = { _secret = "/var/lib/secrets/glance/location"; }; } ]; } Loading @@ -84,6 +98,13 @@ in Configuration written to a yaml file that is read by glance. See <https://github.com/glanceapp/glance/blob/main/docs/configuration.md> for more. Settings containing secret data should be set to an attribute set containing the attribute <literal>_secret</literal> - a string pointing to a file containing the value the option should be set to. See the example in `services.glance.settings.pages` at the weather widget with a location secret to get a better picture of this. ''; }; Loading @@ -102,13 +123,41 @@ in description = "Glance feed dashboard server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = [ pkgs.replace-secret ]; serviceConfig = { ExecStart = ExecStartPre = let glance-yaml = settingsFormat.generate "glance.yaml" cfg.settings; findSecrets = data: if isAttrs data then if data ? _secret then [ data ] else concatLists (map (attr: findSecrets (getAttr attr data)) (attrNames data)) else if isList data then concatLists (map findSecrets data) else [ ]; secretPaths = catAttrs "_secret" (findSecrets cfg.settings); mkSecretReplacement = secretPath: '' replace-secret ${ lib.escapeShellArgs [ "_secret: ${secretPath}" secretPath mergedSettingsFile ] } ''; secretReplacements = concatMapStrings mkSecretReplacement secretPaths; in "${getExe cfg.package} --config ${glance-yaml}"; # Use "+" to run as root because the secrets may not be accessible to glance "+" + pkgs.writeShellScript "glance-start-pre" '' install -m 600 -o $USER ${settingsFile} ${mergedSettingsFile} ${secretReplacements} ''; ExecStart = "${getExe cfg.package} --config ${mergedSettingsFile}"; WorkingDirectory = "/var/lib/glance"; StateDirectory = "glance"; RuntimeDirectory = "glance"; Loading
nixos/tests/glance.nix +42 −6 Original line number Diff line number Diff line Loading @@ -5,19 +5,47 @@ nodes = { machine_default = { pkgs, ... }: { ... }: { services.glance = { enable = true; }; }; machine_custom_port = machine_configured = { pkgs, ... }: let # Do not use this in production. This will make the secret world-readable # in the Nix store secrets.glance-location.path = builtins.toString ( pkgs.writeText "location-secret" "Nivelles, Belgium" ); in { services.glance = { enable = true; settings.server.port = 5678; settings = { server.port = 5678; pages = [ { name = "Home"; columns = [ { size = "full"; widgets = [ { type = "calendar"; } { type = "weather"; location = { _secret = secrets.glance-location.path; }; } ]; } ]; } ]; }; }; }; }; Loading @@ -25,23 +53,31 @@ extraPythonPackages = p: with p; [ beautifulsoup4 pyyaml types-pyyaml types-beautifulsoup4 ]; testScript = '' from bs4 import BeautifulSoup import yaml machine_default.start() machine_default.wait_for_unit("glance.service") machine_default.wait_for_open_port(8080) machine_custom_port.start() machine_custom_port.wait_for_unit("glance.service") machine_custom_port.wait_for_open_port(5678) machine_configured.start() machine_configured.wait_for_unit("glance.service") machine_configured.wait_for_open_port(5678) soup = BeautifulSoup(machine_default.succeed("curl http://localhost:8080")) expected_version = "v${config.nodes.machine_default.services.glance.package.version}" assert any(a.text == expected_version for a in soup.select(".footer a")) yaml_contents = machine_configured.succeed("cat /run/glance/glance.yaml") yaml_parsed = yaml.load(yaml_contents, Loader=yaml.FullLoader) location = yaml_parsed["pages"][0]["columns"][0]["widgets"][1]["location"] assert location == "Nivelles, Belgium" ''; meta.maintainers = [ lib.maintainers.drupol ]; Loading