Subject: bug#32141: closed (Re: [bug#32141] [PATCH] services: Add ddclient service.)

From: [email-masked] (GNU bug Tracking System)
Date: Wed, 29 Aug 2018 22:46:02 +0000

Your bug report

#32141: [PATCH] services: Add ddclient service.

which was filed against the guix-patches package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
32141: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=32141
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: [bug#32141] [PATCH] services: Add ddclient service.
From: Oleg Pykhalov <[email-masked]>
To: [email-masked] (Ludovic Courtès)
Cc: [email-masked]
Date: Thu, 30 Aug 2018 01:45:27 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi Ludovic,

[email-masked] (Ludovic Courtès) writes:

> Sorry for the delay, I had forgotten about this patch.  (Feel free to
> ping when that happens!)

No problem.  OK.  Feel free the same and thank you for pinging me.

> Oleg Pykhalov <[email-masked]> skribis:

[…]

>> +By default, the @code{secret-file} in @code{ddclient-configuration} is
>> +pointing to @file{/etc/ddclient/secrets.conf} file, which will be appended to
>> +@file{/etc/ddclient/ddclient.conf} and should be created in advance.  See
>> +samples inside @file{/share/ddclient} directory of @code{ddclient} package.
>
> I propose slightly different wording, to make it clear that users are
> expected to provide the secret file:
>
>   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.
>
> WDYT?

It looks more clear.  I will apply this, thanks.

>> +@deftypevr {@code{ddclient-configuration} parameter} string secret-file
>> +Secret file which will be appended to ddclient.conf file.
>                                          ^
> @file{ddclient.conf}
>
> Maybe add:
>
>   This file contains credentials for use by ddclient.  You are expected
>   to create it manually.
>
>> +Defaults to @samp{"/etc/ddclient/secrets.conf"}.

Applied.

> OK with changes along these lines.

Pushed as 8490a8346b5c8207f5798be55bea1de865b0bd42

Thanks,
Oleg.

Subject: [PATCH] services: Add ddclient service.
From: Oleg Pykhalov <[email-masked]>
To: [email-masked]
Cc: Oleg Pykhalov <[email-masked]>
Date: Fri, 13 Jul 2018 17:58:54 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

* gnu/services/dns.scm (ddclient-configuration, opaque-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, generate-opaque-ddclient-documentation): New
procedures.
* doc/guix.texi (DNS Services): Document it.
---
 doc/guix.texi        | 107 +++++++++++++++++++++++++++++++++
 gnu/services/dns.scm | 137 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index eaec4c422..fcc7c0037 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -17123,6 +17123,113 @@ When false, disable negative caching.
 @end table
 @end deftp
 
+@subsubheading ddclient Service
+
+@cindex ddclient
+@uref{https://sourceforge.net/projects/ddclient/, ddclient} is an address
+updating utility for dynamic DNS services.
+
+The following example will configure the service with values from
+@file{ddclient.conf} file.  You could get a @file{ddclient.conf} sample from
+@code{ddclient} package.
+
+@example
+(use-modules (ice-9 textual-ports))
+
+(service ddclient-service-type
+         (opaque-ddclient-configuration
+          (ddclient-conf
+           (call-with-input-file "ddclient.conf"
+             get-string-all))))
+@end example
+
+@c %start of fragment
+
+Available @code{opaque-ddclient-configuration} fields are:
+
+@deftypevr {@code{opaque-ddclient-configuration} parameter} package ddclient
+The ddclient package.
+
+@end deftypevr
+
+@deftypevr {@code{opaque-ddclient-configuration} parameter} string ddclient-conf
+The contents of the @file{ddclient.conf} to use.
+
+@end deftypevr
+
+@deftypevr {@code{opaque-ddclient-configuration} parameter} string pid
+The ddclient PID file.
+
+Defaults to @samp{"/var/run/ddclient.pid"}.
+
+@end deftypevr
+
+
+@c %end of fragment
+
+
+@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.pid"}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} boolean ssl
+Enable SSL support.
+
+Defaults to @samp{#t}.
+
+@end deftypevr
+
+@deftypevr {@code{ddclient-configuration} parameter} list extra-options
+Extra options will be appended to ddclient configuration 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 2c57a36b8..7a3184b42 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 <[email-masked]>
+;;; Copyright © 2018 Oleg Pykhalov <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -45,7 +46,11 @@
             zone-entry
 
             dnsmasq-service-type
-            dnsmasq-configuration))
+            dnsmasq-configuration
+
+            ddclient-service-type
+            ddclient-configuration
+            opaque-ddclient-configuration))
 
 ;;;
 ;;; Knot DNS.
@@ -670,3 +675,133 @@
                              (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.pid")
+   "The ddclient PID file.")
+  (ssl
+   (boolean #t)
+   "Enable SSL support.")
+  (extra-options
+   (list '())
+   "Extra options will be appended to ddclient configuration file."))
+
+(define-configuration opaque-ddclient-configuration
+  (ddclient
+   (package ddclient)
+   "The ddclient package.")
+  (ddclient-conf
+   (string (configuration-missing-field 'opaque-ddclient-configuration
+                                        'ddclient-conf))
+   "The contents of the @file{ddclient.conf} to use.")
+  (pid
+   (string "/var/run/ddclient.pid")
+   "The ddclient PID file."))
+
+(define (ddclient-activation config)
+  "Return the activation GEXP for CONFIG."
+  (let ((config-str
+         (if (opaque-ddclient-configuration? config)
+             (opaque-ddclient-configuration-ddclient-conf config)
+             (with-output-to-string
+               (lambda ()
+                 (serialize-configuration config
+                                          ddclient-configuration-fields))))))
+    (with-imported-modules '((guix build utils))
+      #~(begin
+          (use-modules (guix build utils))
+          (mkdir-p "/var/cache/ddclient")
+          ;; 'ddclient' complains about ddclient.conf file permissions, which
+          ;; rules out /gnu/store.  Thus we copy the ddclient.conf to /etc.
+          (mkdir-p "/etc/ddclient")
+          (let ((file "/etc/ddclient/ddclient.conf"))
+            (copy-file #$(plain-file "ddclient.conf" config-str) file)
+            (chmod file #o600))))))
+
+(define (ddclient-shepherd-service config)
+  "Return a <shepherd-service> for ddclient with CONFIG."
+  (let* ((opaque-config? (opaque-ddclient-configuration? config))
+         (pid (if opaque-config?
+                  (opaque-ddclient-configuration-pid config)
+                  (ddclient-configuration-pid config)))
+         (ddclient (if opaque-config?
+                       (opaque-ddclient-configuration-ddclient config)
+                       (ddclient-configuration-ddclient 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"
+                           "-debug" "-verbose")
+                     #:pid-file #$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")))
+           (stop #~(make-kill-destructor))))))
+
+(define ddclient-service-type
+  (service-type
+   (name 'ddclient)
+   (extensions
+    (list (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))
+
+(define (generate-opaque-ddclient-documentation)
+  (generate-documentation
+   `((opaque-ddclient-configuration ,opaque-ddclient-configuration-fields))
+   'opaque-ddclient-configuration))
-- 
2.18.0