From 642c8a8d8dae5047d5020578d36558a3dea465ce Mon Sep 17 00:00:00 2001 From: Peter Hoeg Date: Mon, 12 Mar 2018 23:25:28 +0800 Subject: [PATCH] nixos ddclient: support multiple domains and run via systemd timer a) Some providers can update multiple domains - support that. b) Make "zone" and "script" configurable. Some providers require these. c) Instead of leaving the ddclient daemon running all the time, use a systemd timer to kick it off. d) Don't use a predefined user - run everything via DynamicUser e) Add documentation --- nixos/modules/misc/ids.nix | 4 +- nixos/modules/rename.nix | 2 + .../modules/services/networking/ddclient.nix | 114 +++++++++--------- pkgs/tools/networking/ddclient/default.nix | 6 + 4 files changed, 70 insertions(+), 56 deletions(-) diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 39a24cfecc53..0aad2e7adc2a 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -56,7 +56,7 @@ #dialout = 27; # unused polkituser = 28; #utmp = 29; # unused - ddclient = 30; + # ddclient = 30; # converted to DynamicUser = true davfs2 = 31; #disnix = 33; # unused osgi = 34; @@ -343,7 +343,7 @@ dialout = 27; #polkituser = 28; # currently unused, polkitd doesn't need a group utmp = 29; - ddclient = 30; + # ddclient = 30; # converted to DynamicUser = true davfs2 = 31; disnix = 33; osgi = 34; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 489d7d8b9b50..dbd671029509 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -22,6 +22,8 @@ with lib; (config: let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config; in if enabled then [ pkgs.gutenprint ] else [ ])) + (mkRenamedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ]) + (mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "") (mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ]) (mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ]) (mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ]) diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index 9e56545f746c..9a2e13e9553c 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -3,24 +3,24 @@ let cfg = config.services.ddclient; boolToStr = bool: if bool then "yes" else "no"; + dataDir = "/var/lib/ddclient"; configText = '' # This file can be used as a template for configFile or is automatically generated by Nix options. - daemon=${toString cfg.interval} - cache=${cfg.homeDir}/ddclient.cache - pid=/run/ddclient/ddclient.pid - foreground=NO + cache=${dataDir}/ddclient.cache + foreground=YES use=${cfg.use} login=${cfg.username} password=${cfg.password} protocol=${cfg.protocol} - ${let server = cfg.server; in - lib.optionalString (server != "") "server=${server}"} + ${lib.optionalString (cfg.script != "") "script=${cfg.script}"} + ${lib.optionalString (cfg.server != "") "server=${cfg.server}"} + ${lib.optionalString (cfg.zone != "") "zone=${cfg.zone}"} ssl=${boolToStr cfg.ssl} wildcard=YES quiet=${boolToStr cfg.quiet} verbose=${boolToStr cfg.verbose} - ${cfg.domain} + ${lib.concatStringsSep "," cfg.domains} ${cfg.extraConfig} ''; @@ -44,17 +44,11 @@ with lib; ''; }; - homeDir = mkOption { - default = "/var/lib/ddclient"; - type = str; - description = "Home directory for the daemon user."; - }; - - domain = mkOption { - default = ""; - type = str; + domains = mkOption { + default = [ "" ]; + type = listOf str; description = '' - Domain name to synchronize. + Domain name(s) to synchronize. ''; }; @@ -62,7 +56,7 @@ with lib; default = ""; type = str; description = '' - Username. + User name. ''; }; @@ -75,9 +69,12 @@ with lib; }; interval = mkOption { - default = 600; - type = int; - description = "The interval at which to run the check and update."; + default = "10min"; + type = str; + description = '' + The interval at which to run the check and update. + See man 7 systemd.time for the format. + ''; }; configFile = mkOption { @@ -95,7 +92,7 @@ with lib; default = "dyndns2"; type = str; description = '' - Protocol to use with dynamic DNS provider (see http://sourceforge.net/apps/trac/ddclient/wiki/Protocols). + Protocol to use with dynamic DNS provider (see https://sourceforge.net/p/ddclient/wiki/protocols). ''; }; @@ -115,11 +112,20 @@ with lib; ''; }; - extraConfig = mkOption { - default = ""; - type = lines; + + quiet = mkOption { + default = false; + type = bool; description = '' - Extra configuration. Contents will be added verbatim to the configuration file. + Print no messages for unnecessary updates. + ''; + }; + + script = mkOption { + default = ""; + type = str; + description = '' + script as required by some providers. ''; }; @@ -139,11 +145,19 @@ with lib; ''; }; - quiet = mkOption { - default = false; - type = bool; + zone = mkOption { + default = ""; + type = str; description = '' - Print no messages for unnecessary updates. + zone as required by some providers. + ''; + }; + + extraConfig = mkOption { + default = ""; + type = lines; + description = '' + Extra configuration. Contents will be added verbatim to the configuration file. ''; }; }; @@ -153,23 +167,8 @@ with lib; ###### implementation config = mkIf config.services.ddclient.enable { - - users = { - extraGroups.ddclient.gid = config.ids.gids.ddclient; - - extraUsers.ddclient = { - uid = config.ids.uids.ddclient; - description = "ddclient daemon user"; - group = "ddclient"; - home = cfg.homeDir; - createHome = true; - }; - }; - environment.etc."ddclient.conf" = { enable = cfg.configFile == "/etc/ddclient.conf"; - uid = config.ids.uids.ddclient; - gid = config.ids.gids.ddclient; mode = "0600"; text = configText; }; @@ -180,15 +179,22 @@ with lib; after = [ "network.target" ]; restartTriggers = [ config.environment.etc."ddclient.conf".source ]; - serviceConfig = { - RuntimeDirectory = "ddclient"; - # we cannot run in forking mode as it swallows all the program output - Type = "simple"; - User = "ddclient"; - Group = "ddclient"; - ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -foreground -file ${cfg.configFile}"; - ProtectSystem = "full"; - PrivateTmp = true; + serviceConfig = rec { + DynamicUser = true; + RuntimeDirectory = StateDirectory; + StateDirectory = builtins.baseNameOf dataDir; + Type = "oneshot"; + ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m666 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf"; + ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf"; + }; + }; + + systemd.timers.ddclient = { + description = "Run ddclient"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = cfg.interval; + OnUnitInactiveSec = cfg.interval; }; }; }; diff --git a/pkgs/tools/networking/ddclient/default.nix b/pkgs/tools/networking/ddclient/default.nix index 6d3ca27df1d6..93828c10d135 100644 --- a/pkgs/tools/networking/ddclient/default.nix +++ b/pkgs/tools/networking/ddclient/default.nix @@ -9,6 +9,7 @@ buildPerlPackage rec { sha256 = "1j8zdn7fy7i0bjk3jf0hxnbnshc2yf054vxq64imxdpfd7n5zgfy"; }; + # perl packages by default get devdoc which isn't present outputs = [ "out" ]; buildInputs = with perlPackages; [ IOSocketSSL DigestSHA1 ]; @@ -25,7 +26,12 @@ buildPerlPackage rec { ''; installPhase = '' + runHook preInstall + install -Dm755 ddclient $out/bin/ddclient + install -Dm644 -t $out/share/doc/ddclient COP* ChangeLog README.* RELEASENOTE + + runHook postInstall ''; # there are no tests distributed with ddclient