the conversion procedure is simple: - find all things that look like options, ie calls to either `mkOption` or `lib.mkOption` that take an attrset. remember the attrset as the option - for all options, find a `description` attribute who's value is not a call to `mdDoc` or `lib.mdDoc` - textually convert the entire value of the attribute to MD with a few simple regexes (the set from mdize-module.sh) - if the change produced a change in the manual output, discard - if the change kept the manual unchanged, add some text to the description to make sure we've actually found an option. if the manual changes this time, keep the converted description this procedure converts 80% of nixos options to markdown. around 2000 options remain to be inspected, but most of those fail the "does not change the manual output check": currently the MD conversion process does not faithfully convert docbook tags like <code> and <package>, so any option using such tags will not be converted at all.
239 lines
6.8 KiB
Nix
239 lines
6.8 KiB
Nix
{ config, pkgs, lib, ... }:
|
|
|
|
let
|
|
cfg = config.services.ddclient;
|
|
boolToStr = bool: if bool then "yes" else "no";
|
|
dataDir = "/var/lib/ddclient";
|
|
StateDirectory = builtins.baseNameOf dataDir;
|
|
RuntimeDirectory = StateDirectory;
|
|
|
|
configFile' = pkgs.writeText "ddclient.conf" ''
|
|
# This file can be used as a template for configFile or is automatically generated by Nix options.
|
|
cache=${dataDir}/ddclient.cache
|
|
foreground=YES
|
|
use=${cfg.use}
|
|
login=${cfg.username}
|
|
password=${if cfg.protocol == "nsupdate" then "/run/${RuntimeDirectory}/ddclient.key" else "@password_placeholder@"}
|
|
protocol=${cfg.protocol}
|
|
${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
|
|
ipv6=${boolToStr cfg.ipv6}
|
|
quiet=${boolToStr cfg.quiet}
|
|
verbose=${boolToStr cfg.verbose}
|
|
${cfg.extraConfig}
|
|
${lib.concatStringsSep "," cfg.domains}
|
|
'';
|
|
configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
|
|
|
|
preStart = ''
|
|
install ${configFile} /run/${RuntimeDirectory}/ddclient.conf
|
|
${lib.optionalString (cfg.configFile == null) (if (cfg.protocol == "nsupdate") then ''
|
|
install ${cfg.passwordFile} /run/${RuntimeDirectory}/ddclient.key
|
|
'' else if (cfg.passwordFile != null) then ''
|
|
"${pkgs.replace-secret}/bin/replace-secret" "@password_placeholder@" "${cfg.passwordFile}" "/run/${RuntimeDirectory}/ddclient.conf"
|
|
'' else ''
|
|
sed -i '/^password=@password_placeholder@$/d' /run/${RuntimeDirectory}/ddclient.conf
|
|
'')}
|
|
'';
|
|
|
|
in
|
|
|
|
with lib;
|
|
|
|
{
|
|
|
|
imports = [
|
|
(mkChangedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ]
|
|
(config:
|
|
let value = getAttrFromPath [ "services" "ddclient" "domain" ] config;
|
|
in if value != "" then [ value ] else []))
|
|
(mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "")
|
|
(mkRemovedOptionModule [ "services" "ddclient" "password" ] "Use services.ddclient.passwordFile instead.")
|
|
];
|
|
|
|
###### interface
|
|
|
|
options = {
|
|
|
|
services.ddclient = with lib.types; {
|
|
|
|
enable = mkOption {
|
|
default = false;
|
|
type = bool;
|
|
description = lib.mdDoc ''
|
|
Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org).
|
|
'';
|
|
};
|
|
|
|
package = mkOption {
|
|
type = package;
|
|
default = pkgs.ddclient;
|
|
defaultText = "pkgs.ddclient";
|
|
description = lib.mdDoc ''
|
|
The ddclient executable package run by the service.
|
|
'';
|
|
};
|
|
|
|
domains = mkOption {
|
|
default = [ "" ];
|
|
type = listOf str;
|
|
description = lib.mdDoc ''
|
|
Domain name(s) to synchronize.
|
|
'';
|
|
};
|
|
|
|
username = mkOption {
|
|
# For `nsupdate` username contains the path to the nsupdate executable
|
|
default = lib.optionalString (config.services.ddclient.protocol == "nsupdate") "${pkgs.bind.dnsutils}/bin/nsupdate";
|
|
defaultText = "";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
User name.
|
|
'';
|
|
};
|
|
|
|
passwordFile = mkOption {
|
|
default = null;
|
|
type = nullOr str;
|
|
description = lib.mdDoc ''
|
|
A file containing the password or a TSIG key in named format when using the nsupdate protocol.
|
|
'';
|
|
};
|
|
|
|
interval = mkOption {
|
|
default = "10min";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
The interval at which to run the check and update.
|
|
See {command}`man 7 systemd.time` for the format.
|
|
'';
|
|
};
|
|
|
|
configFile = mkOption {
|
|
default = null;
|
|
type = nullOr path;
|
|
description = lib.mdDoc ''
|
|
Path to configuration file.
|
|
When set this overrides the generated configuration from module options.
|
|
'';
|
|
example = "/root/nixos/secrets/ddclient.conf";
|
|
};
|
|
|
|
protocol = mkOption {
|
|
default = "dyndns2";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
Protocol to use with dynamic DNS provider (see https://sourceforge.net/p/ddclient/wiki/protocols).
|
|
'';
|
|
};
|
|
|
|
server = mkOption {
|
|
default = "";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
Server address.
|
|
'';
|
|
};
|
|
|
|
ssl = mkOption {
|
|
default = true;
|
|
type = bool;
|
|
description = lib.mdDoc ''
|
|
Whether to use SSL/TLS to connect to dynamic DNS provider.
|
|
'';
|
|
};
|
|
|
|
ipv6 = mkOption {
|
|
default = false;
|
|
type = bool;
|
|
description = lib.mdDoc ''
|
|
Whether to use IPv6.
|
|
'';
|
|
};
|
|
|
|
|
|
quiet = mkOption {
|
|
default = false;
|
|
type = bool;
|
|
description = lib.mdDoc ''
|
|
Print no messages for unnecessary updates.
|
|
'';
|
|
};
|
|
|
|
script = mkOption {
|
|
default = "";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
script as required by some providers.
|
|
'';
|
|
};
|
|
|
|
use = mkOption {
|
|
default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
Method to determine the IP address to send to the dynamic DNS provider.
|
|
'';
|
|
};
|
|
|
|
verbose = mkOption {
|
|
default = false;
|
|
type = bool;
|
|
description = lib.mdDoc ''
|
|
Print verbose information.
|
|
'';
|
|
};
|
|
|
|
zone = mkOption {
|
|
default = "";
|
|
type = str;
|
|
description = lib.mdDoc ''
|
|
zone as required by some providers.
|
|
'';
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
default = "";
|
|
type = lines;
|
|
description = lib.mdDoc ''
|
|
Extra configuration. Contents will be added verbatim to the configuration file.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
###### implementation
|
|
|
|
config = mkIf config.services.ddclient.enable {
|
|
systemd.services.ddclient = {
|
|
description = "Dynamic DNS Client";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" ];
|
|
restartTriggers = optional (cfg.configFile != null) cfg.configFile;
|
|
|
|
serviceConfig = {
|
|
DynamicUser = true;
|
|
RuntimeDirectoryMode = "0700";
|
|
inherit RuntimeDirectory;
|
|
inherit StateDirectory;
|
|
Type = "oneshot";
|
|
ExecStartPre = "!${pkgs.writeShellScript "ddclient-prestart" preStart}";
|
|
ExecStart = "${lib.getBin cfg.package}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf";
|
|
};
|
|
};
|
|
|
|
systemd.timers.ddclient = {
|
|
description = "Run ddclient";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnBootSec = cfg.interval;
|
|
OnUnitInactiveSec = cfg.interval;
|
|
};
|
|
};
|
|
};
|
|
}
|