summary refs log tree commit diff
diff options
context:
space:
mode:
authorOleg Pykhalov <go.wigust@gmail.com>2018-07-13 11:49:13 +0300
committerOleg Pykhalov <go.wigust@gmail.com>2018-08-30 01:19:47 +0300
commit8490a8346b5c8207f5798be55bea1de865b0bd42 (patch)
tree4123b5d1d4f868ecf68d82428b495cdf9a6bf610
parent4db7a9dc663c5b26e45ec35538bf68ff87acdf7b (diff)
downloadguix-8490a8346b5c8207f5798be55bea1de865b0bd42.tar.gz
services: Add ddclient service.
* gnu/services/dns.scm (ddclient-configuration, ddclient-service-type): New
variables.
(uglify-field-name, serialize-field, serialize-boolean, serialize-integer,
serialize-string, serialize-list, serialize-extra-options,
ddclient-activation, ddclient-shepherd-service,
generate-ddclient-documentation): New procedures.
* doc/guix.texi (DNS Services): Document it.
-rw-r--r--doc/guix.texi108
-rw-r--r--gnu/services/dns.scm168
2 files changed, 275 insertions, 1 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index cd0e74a2d7..97631d52e4 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -17263,6 +17263,114 @@ When false, disable negative caching.
 @end table
 @end deftp
 
+@subsubheading ddclient Service
+
+@cindex ddclient
+The ddclient service described below runs the ddclient daemon, which takes
+care of automatically updating DNS entries for service providers such as
+@uref{https://dyn.com/dns/, Dyn}.
+
+The following example show instantiates the service with its default
+configuration:
+
+@example
+(service ddclient-service-type)
+@end example
+
+Note that ddclient needs to access credentials that are stored in a
+@dfn{secret file}, by default @file{/etc/ddclient/secrets} (see
+@code{secret-file} below.)  You are expected to create this file manually, in
+an ``out-of-band'' fashion (you @emph{could} make this file part of the
+service configuration, for instance by using @code{plain-file}, but it will be
+world-readable @i{via} @file{/gnu/store}.)  See the examples in the
+@file{share/ddclient} directory of the @code{ddclient} package.
+
+@c %start of fragment
+
+Available @code{ddclient-configuration} fields are:
+
+@deftypevr {@code{ddclient-configuration} parameter} package ddclient
+The ddclient package.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} integer daemon
+The period after which ddclient will retry to check IP and domain name.
+
+Defaults to @samp{300}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} boolean syslog
+Use syslog for the output.
+
+Defaults to @samp{#t}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string mail
+Mail to user.
+
+Defaults to @samp{"root"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string mail-failure
+Mail failed update to user.
+
+Defaults to @samp{"root"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string pid
+The ddclient PID file.
+
+Defaults to @samp{"/var/run/ddclient/ddclient.pid"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} boolean ssl
+Enable SSL support.
+
+Defaults to @samp{#t}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string user
+Specifies the user name or ID that is used when running ddclient
+program.
+
+Defaults to @samp{"ddclient"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string group
+Group of the user who will run the ddclient program.
+
+Defaults to @samp{"ddclient"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} string secret-file
+Secret file which will be appended to @file{ddclient.conf} file.  This
+file contains credentials for use by ddclient.  You are expected to
+create it manually.
+
+Defaults to @samp{"/etc/ddclient/secrets.conf"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} list extra-options
+Extra options will be appended to @file{ddclient.conf} file.
+
+Defaults to @samp{()}.
+
+@end deftypevr
+
+
+@c %end of fragment
+
+
 @node VPN Services
 @subsubsection VPN Services
 @cindex VPN (virtual private network)
diff --git a/gnu/services/dns.scm b/gnu/services/dns.scm
index 2c57a36b84..16bd039f59 100644
--- a/gnu/services/dns.scm
+++ b/gnu/services/dns.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2017 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -45,7 +46,10 @@
             zone-entry
 
             dnsmasq-service-type
-            dnsmasq-configuration))
+            dnsmasq-configuration
+
+            ddclient-service-type
+            ddclient-configuration))
 
 ;;;
 ;;; Knot DNS.
@@ -670,3 +674,165 @@
                              (compose list dnsmasq-shepherd-service))))
    (default-value (dnsmasq-configuration))
    (description "Run the dnsmasq DNS server.")))
+
+
+;;;
+;;; ddclient
+;;;
+
+(define (uglify-field-name field-name)
+  (string-delete #\? (symbol->string field-name)))
+
+(define (serialize-field field-name val)
+  (format #t "~a=~a\n" (uglify-field-name field-name) val))
+
+(define (serialize-boolean field-name val)
+  (serialize-field field-name (if val "yes" "no")))
+
+(define (serialize-integer field-name val)
+  (serialize-field field-name (number->string val)))
+
+(define (serialize-string field-name val)
+  (if (and (string? val) (string=? val ""))
+      ""
+      (serialize-field field-name val)))
+
+(define (serialize-list field-name val)
+  (if (null? val) "" (serialize-field field-name (string-join val))))
+
+(define (serialize-extra-options extra-options)
+  (string-join extra-options "\n" 'suffix))
+
+(define-configuration ddclient-configuration
+  (ddclient
+   (package ddclient)
+   "The ddclient package.")
+  (daemon
+   (integer 300)
+   "The period after which ddclient will retry to check IP and domain name.")
+  (syslog
+   (boolean #t)
+   "Use syslog for the output.")
+  (mail
+   (string "root")
+   "Mail to user.")
+  (mail-failure
+   (string "root")
+   "Mail failed update to user.")
+  (pid
+   (string "/var/run/ddclient/ddclient.pid")
+   "The ddclient PID file.")
+  (ssl
+   (boolean #t)
+   "Enable SSL support.")
+  (user
+   (string "ddclient")
+   "Specifies the user name or ID that is used when running ddclient
+program.")
+  (group
+   (string "ddclient")
+   "Group of the user who will run the ddclient program.")
+  (secret-file
+   (string "/etc/ddclient/secrets.conf")
+   "Secret file which will be appended to @file{ddclient.conf} file.  This
+file contains credentials for use by ddclient.  You are expected to create it
+manually.")
+  (extra-options
+   (list '())
+   "Extra options will be appended to @file{ddclient.conf} file."))
+
+(define (ddclient-account config)
+  "Return the user accounts and user groups for CONFIG."
+  (let ((ddclient-user (ddclient-configuration-user config))
+        (ddclient-group (ddclient-configuration-group config)))
+    (list (user-group
+           (name ddclient-group)
+           (system? #t))
+          (user-account
+           (name ddclient-user)
+           (system? #t)
+           (group ddclient-group)
+           (comment "ddclientd privilege separation user")
+           (home-directory (string-append "/var/run/" ddclient-user))))))
+
+(define (ddclient-activation config)
+  "Return the activation GEXP for CONFIG."
+  (with-imported-modules '((guix build utils)
+                           (ice-9 rdelim))
+    #~(begin
+        (use-modules (guix build utils)
+                     (ice-9 rdelim))
+        (let ((ddclient-user
+               #$(passwd:uid (getpw (ddclient-configuration-user config))))
+              (ddclient-group
+               #$(passwd:gid (getpw (ddclient-configuration-group config))))
+              (ddclient-secret-file
+               #$(ddclient-configuration-secret-file config)))
+          ;; 'ddclient' complains about ddclient.conf file permissions, which
+          ;; rules out /gnu/store.  Thus we copy the ddclient.conf to /etc.
+          (for-each (lambda (dir)
+                      (mkdir-p dir)
+                      (chmod dir #o700)
+                      (chown dir ddclient-user ddclient-group))
+                    '("/var/cache/ddclient" "/var/run/ddclient"
+                      "/etc/ddclient"))
+          (with-output-to-file "/etc/ddclient/ddclient.conf"
+            (lambda ()
+              (display
+               (string-append
+                "# Generated by 'ddclient-service'.\n\n"
+                #$(with-output-to-string
+                    (lambda ()
+                      (serialize-configuration config
+                                               ddclient-configuration-fields)))
+                (if (string-null? ddclient-secret-file)
+                    ""
+                    (format #f "\n\n# Appended from '~a'.\n\n~a"
+                            ddclient-secret-file
+                            (with-input-from-file ddclient-secret-file
+                              read-string)))))))
+          (chmod "/etc/ddclient/ddclient.conf" #o600)
+          (chown "/etc/ddclient/ddclient.conf"
+                 ddclient-user ddclient-group)))))
+
+(define (ddclient-shepherd-service config)
+  "Return a <shepherd-service> for ddclient with CONFIG."
+  (let ((ddclient (ddclient-configuration-ddclient config))
+        (ddclient-pid (ddclient-configuration-pid config))
+        (ddclient-user (ddclient-configuration-user config))
+        (ddclient-group (ddclient-configuration-group config)))
+    (list (shepherd-service
+           (provision '(ddclient))
+           (documentation "Run ddclient daemon.")
+           (start #~(make-forkexec-constructor
+                     (list #$(file-append ddclient "/bin/ddclient")
+                           "-foreground"
+                           "-file" "/etc/ddclient/ddclient.conf")
+                     #:pid-file #$ddclient-pid
+                     #:environment-variables
+                     (list "SSL_CERT_DIR=/run/current-system/profile\
+/etc/ssl/certs"
+                           "SSL_CERT_FILE=/run/current-system/profile\
+/etc/ssl/certs/ca-certificates.crt")
+                     #:user #$ddclient-user
+                     #:group #$ddclient-group))
+           (stop #~(make-kill-destructor))))))
+
+(define ddclient-service-type
+  (service-type
+   (name 'ddclient)
+   (extensions
+    (list (service-extension account-service-type
+                             ddclient-account)
+          (service-extension shepherd-root-service-type
+                             ddclient-shepherd-service)
+          (service-extension activation-service-type
+                             ddclient-activation)))
+   (default-value (ddclient-configuration))
+   (description "Configure address updating utility for dynamic DNS services,
+ddclient.")))
+
+(define (generate-ddclient-documentation)
+  (generate-documentation
+   `((ddclient-configuration ,ddclient-configuration-fields))
+   'ddclient-configuration))