From ff6f652641d7fa8e6e2a029239de912c5db26d28 Mon Sep 17 00:00:00 2001 From: Gabriel Arazas Date: Tue, 5 Jul 2022 22:23:19 +0800 Subject: [PATCH] services/archivebox: create service --- modules/nixos/services/archivebox.nix | 179 ++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 modules/nixos/services/archivebox.nix diff --git a/modules/nixos/services/archivebox.nix b/modules/nixos/services/archivebox.nix new file mode 100644 index 00000000..a6a27e63 --- /dev/null +++ b/modules/nixos/services/archivebox.nix @@ -0,0 +1,179 @@ +{ config, options, lib, pkgs, ... }: + +let + cfg = config.services.archivebox; + jobType = { name, options, ... }: { + options = { + links = lib.mkOption { + type = with lib.types; listOf str; + description = "List of links to archive."; + example = lib.literalExpression '' + [ + "https://guix.gnu.org/feeds/blog.atom" + "https://nixos.org/blog/announcements-rss.xml" + ] + ''; + }; + + extraArgs = lib.mkOption { + type = with lib.types; listOf str; + description = '' + Additional arguments for adding links (i.e., archivebox add + $LINK) from . + ''; + default = [ ]; + example = lib.literalExpression '' + [ "--depth 1" ] + ''; + }; + + startAt = lib.mkOption { + type = with lib.types; str; + description = '' + Indicates how frequent the scheduled archiving will occur. + Should be a valid string format as described from systemd.time(5). + ''; + default = "weekly"; + defaultText = "weekly"; + example = "*-*-01/2"; + }; + }; + }; +in { + options.services.archivebox = { + enable = lib.mkEnableOption "Archivebox service"; + + archivePath = lib.mkOption { + type = with lib.types; either path str; + description = "The path of the Archivebox archive."; + example = "\${config.xdg.dataHome}/archivebox"; + }; + + jobs = lib.mkOption { + type = with lib.types; attrsOf (submodule jobType); + description = "A map of archiving tasks for the service."; + default = { }; + defaultText = lib.literalExpression "{}"; + example = lib.literalExpression '' + { + illustration = { + links = [ + "https://www.davidrevoy.com/" + "https://www.youtube.com/c/ronillust" + ]; + startAt = "weekly"; + }; + + research = { + links = [ + "https://arxiv.org/rss/cs" + "https://distill.pub/" + ]; + extraArgs = [ "--depth 1" ]; + startAt = "daily"; + }; + } + ''; + }; + + withDependencies = + lib.mkEnableOption "additional dependencies to be installed"; + + webserver = { + enable = lib.mkEnableOption "web UI for Archivebox"; + + port = lib.mkOption { + type = lib.types.port; + description = "The port number to be used for the server at localhost."; + default = 8000; + example = 8888; + }; + }; + }; + + config = let + pkgSet = [ pkgs.archivebox ] ++ (lib.optionals cfg.withDependencies + (with pkgs; [ chromium nodejs_latest wget curl youtube-dl ])); + in lib.mkIf cfg.enable { + systemd.services = lib.mkMerge [ + (lib.mapAttrs' (name: value: + lib.nameValuePair "archivebox-add-${name}" { + description = + "Archivebox archive group '${name}' for ${cfg.archivePath}"; + after = [ "network.target" ]; + documentation = [ "https://docs.archivebox.io/" ]; + path = with pkgs; + [ ripgrep coreutils ] ++ pkgSet ++ [ config.programs.git.package ]; + script = '' + echo "${lib.concatStringsSep "\n" value.links}" \ + | archivebox add ${lib.concatStringsSep " " value.extraArgs} + ''; + serviceConfig = { + LockPersonality = true; + NoNewPrivileges = true; + PrivateTmp = true; + PrivateUsers = true; + PrivateDevices = true; + ProtectControlGroups = true; + ProtectClock = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + WorkingDirectory = cfg.archivePath; + }; + unitConfig = { + AssertPathIsReadWrite = cfg.archivePath; + AssertPathIsDirectory = cfg.archivePath; + }; + }) cfg.jobs) + + (lib.mkIf cfg.webserver.enable { + archivebox-server = { + description = "Archivebox server for ${cfg.archivePath}"; + after = [ "network.target" ]; + documentation = [ "https://docs.archivebox.io/" ]; + wantedBy = [ "graphical-session.target" ]; + serviceConfig = { + ExecStart = "${pkgs.archivebox}/bin/archivebox server localhost:${ + toString cfg.webserver.port + }"; + Restart = "on-failure"; + LockPersonality = true; + NoNewPrivileges = true; + PrivateTmp = true; + PrivateUsers = true; + PrivateDevices = true; + ProtectControlGroups = true; + ProtectClock = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + WorkingDirectory = cfg.archivePath; + }; + unitConfig = { + AssertPathIsReadWrite = cfg.archivePath; + AssertPathIsDirectory = cfg.archivePath; + }; + }; + }) + ]; + + systemd.timers = lib.mapAttrs' (name: value: + lib.nameValuePair "archivebox-add-${name}" { + description = + "Archivebox archive group '${name}' for ${cfg.archivePath}"; + after = [ "network.target" ]; + documentation = [ "https://docs.archivebox.io/" ]; + timerConfig = { + Persistent = true; + OnCalendar = value.startAt; + RandomizedDelaySec = 120; + }; + wantedBy = [ "timers.target" ]; + }) cfg.jobs; + }; +}