unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#32141] [PATCH] services: Add ddclient service.
@ 2018-07-13 14:58 Oleg Pykhalov
  2018-07-19  9:40 ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Oleg Pykhalov @ 2018-07-13 14:58 UTC (permalink / raw)
  To: 32141

* 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 <julien@lepiller.eu>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;;
 ;;; 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.")))
+
+\f
+;;;
+;;; 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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [bug#32141] [PATCH] services: Add ddclient service.
  2018-07-13 14:58 [bug#32141] [PATCH] services: Add ddclient service Oleg Pykhalov
@ 2018-07-19  9:40 ` Ludovic Courtès
  2018-07-25  7:22   ` Oleg Pykhalov
  0 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2018-07-19  9:40 UTC (permalink / raw)
  To: Oleg Pykhalov; +Cc: 32141

Hi Oleg,

Oleg Pykhalov <go.wigust@gmail.com> skribis:

> * 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.

[...]

> +@subsubheading ddclient Service
> +
> +@cindex ddclient
> +@uref{https://sourceforge.net/projects/ddclient/, ddclient} is an address
> +updating utility for dynamic DNS services.

It would be nice to expound a bit, like:

  The ddclient service described below runs the ddclient daemon, which
  takes care of automatically updating DNS entries for service providers
  such as DynDNS.com.

Also, is there a better home page?

Otherwise LGTM!

> +    (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))))))

Does it run as root?  If there’s no option to run it (mostly) as
non-root, perhaps it would make sense to try using
‘make-forkexec-constructor/container’ here (as a separate patch.)

WDYT?

Thank you,
Ludo’.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#32141] [PATCH] services: Add ddclient service.
  2018-07-19  9:40 ` Ludovic Courtès
@ 2018-07-25  7:22   ` Oleg Pykhalov
  2018-07-26  8:51     ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Oleg Pykhalov @ 2018-07-25  7:22 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 32141

[-- Attachment #1: Type: text/plain, Size: 2949 bytes --]

Hello Ludovic,

Thank you for review.

ludo@gnu.org (Ludovic Courtès) writes:

> Oleg Pykhalov <go.wigust@gmail.com> skribis:
>
>> * 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.
>
> [...]
>
>> +@subsubheading ddclient Service
>> +
>> +@cindex ddclient
>> +@uref{https://sourceforge.net/projects/ddclient/, ddclient} is an address
>> +updating utility for dynamic DNS services.
>
> It would be nice to expound a bit, like:
>
>   The ddclient service described below runs the ddclient daemon, which
>   takes care of automatically updating DNS entries for service providers
>   such as DynDNS.com.

OK.  I improved little bit with “such as @uref{https://dyn.com/dns/,
Dyn}.” if you don't mind.

> Also, is there a better home page?

I think no.  I found http://ddclient.sf.net/ in Debian package recipe
[1], but ‘curl -Ik --location http://ddclient.sf.net/’ returns a
https://sourceforge.net/p/ddclient/wiki/Home/ URI.

> Otherwise LGTM!
>
>> +    (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))))))
>
> Does it run as root?  If there’s no option to run it (mostly) as
> non-root, perhaps it would make sense to try using
> ‘make-forkexec-constructor/container’ here (as a separate patch.)
>
> WDYT?

It did run as root.  I've succeeded to run it with ‘ddclient’ user.


Also, the generated ‘ddclient.conf’ which contains secrets is stored in
the store.  I probably should change the ‘ddclient-activation’ procedure

--8<---------------cut here---------------start------------->8---
(copy-file #$(plain-file "ddclient.conf" config-str) file)
--8<---------------cut here---------------end--------------->8---

to a procedure which writes ‘config-str’ to the file without storing it
somewhere else.  WDYT?


[1]  https://packages.debian.org/stretch/ddclient

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#32141] [PATCH] services: Add ddclient service.
  2018-07-25  7:22   ` Oleg Pykhalov
@ 2018-07-26  8:51     ` Ludovic Courtès
  2018-08-01 17:27       ` Oleg Pykhalov
  0 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2018-07-26  8:51 UTC (permalink / raw)
  To: Oleg Pykhalov; +Cc: 32141

Hi Oleg,

Oleg Pykhalov <go.wigust@gmail.com> skribis:

> ludo@gnu.org (Ludovic Courtès) writes:

[...]

>>> +@subsubheading ddclient Service
>>> +
>>> +@cindex ddclient
>>> +@uref{https://sourceforge.net/projects/ddclient/, ddclient} is an address
>>> +updating utility for dynamic DNS services.
>>
>> It would be nice to expound a bit, like:
>>
>>   The ddclient service described below runs the ddclient daemon, which
>>   takes care of automatically updating DNS entries for service providers
>>   such as DynDNS.com.
>
> OK.  I improved little bit with “such as @uref{https://dyn.com/dns/,
> Dyn}.” if you don't mind.

Sure.

>> Does it run as root?  If there’s no option to run it (mostly) as
>> non-root, perhaps it would make sense to try using
>> ‘make-forkexec-constructor/container’ here (as a separate patch.)
>>
>> WDYT?
>
> It did run as root.  I've succeeded to run it with ‘ddclient’ user.

Awesome.

> Also, the generated ‘ddclient.conf’ which contains secrets is stored in
> the store.  I probably should change the ‘ddclient-activation’ procedure
>
> (copy-file #$(plain-file "ddclient.conf" config-str) file)
>
> to a procedure which writes ‘config-str’ to the file without storing it
> somewhere else.  WDYT?

The problem would be the same: the activation script would contain
‘config-str’, and it would live in the store.

In short we must not manipulate secrets in anything that goes through
the store.  The only thing I can suggest is to leave it up to the
user to create a file containing the secret in an out-of-band fashion;
/etc is a good place for such things.

For example, they could create /etc/ddclient-secrets and then we would
somehow arrange to get that file read.

To do that there are two possibilities that come to mind:

  1. If the config file syntax has an “include” directive, just include
     /etc/ddclient-secrets unconditionally in the generated config file.

  2. Write an activation snippet that concatenates the generated config
     file with /etc/ddclient-secrets and stores that as
     /etc/ddclient.conf (or something like that.)

Thoughts?

Ludo’.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#32141] [PATCH] services: Add ddclient service.
  2018-07-26  8:51     ` Ludovic Courtès
@ 2018-08-01 17:27       ` Oleg Pykhalov
  2018-08-27 11:22         ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Oleg Pykhalov @ 2018-08-01 17:27 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 32141


[-- Attachment #1.1: Type: text/plain, Size: 2165 bytes --]

Hello Ludovic,

I applied all your suggestions and updated the documentation.  The patch
is attached below.  I run a ddclient service from this patch currently.

ludo@gnu.org (Ludovic Courtès) writes:

[…]

>> Also, the generated ‘ddclient.conf’ which contains secrets is stored in
>> the store.  I probably should change the ‘ddclient-activation’ procedure
>>
>> (copy-file #$(plain-file "ddclient.conf" config-str) file)
>>
>> to a procedure which writes ‘config-str’ to the file without storing it
>> somewhere else.  WDYT?
>
> The problem would be the same: the activation script would contain
> ‘config-str’, and it would live in the store.
>
> In short we must not manipulate secrets in anything that goes through
> the store.  The only thing I can suggest is to leave it up to the
> user to create a file containing the secret in an out-of-band fashion;
> /etc is a good place for such things.
>
> For example, they could create /etc/ddclient-secrets and then we would
> somehow arrange to get that file read.
>
> To do that there are two possibilities that come to mind:
>
>   1. If the config file syntax has an “include” directive, just include
>      /etc/ddclient-secrets unconditionally in the generated config file.
>
>   2. Write an activation snippet that concatenates the generated config
>      file with /etc/ddclient-secrets and stores that as
>      /etc/ddclient.conf (or something like that.)
>
> Thoughts?

Could we use ‘/etc/ddclient’ directory for secrets file, because
ddclient program use this directory by default?

--8<---------------cut here---------------start------------->8---
The following example will configure the service.

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.

@example
(service ddclient-service-type)
@end example
--8<---------------cut here---------------end--------------->8---


[-- Attachment #1.2: [PATCH] services: Add ddclient service. --]
[-- Type: text/x-patch, Size: 10810 bytes --]

From 3f47ae60ecb2e8780c451e93976b5c83135d8420 Mon Sep 17 00:00:00 2001
From: Oleg Pykhalov <go.wigust@gmail.com>
Date: Fri, 13 Jul 2018 11:49:13 +0300
Subject: [PATCH] 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.
---
 doc/guix.texi        | 103 +++++++++++++++++++++++++++
 gnu/services/dns.scm | 166 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 268 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 080b091b3..e08bfe059 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -17211,6 +17211,109 @@ 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 will configure the service.
+
+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.
+
+@example
+(service ddclient-service-type)
+@end example
+
+
+@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 ddclient.conf file.
+
+Defaults to @samp{"/etc/ddclient/secrets.conf"}.
+
+@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..7ac61dfca 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,163 @@
                              (compose list dnsmasq-shepherd-service))))
    (default-value (dnsmasq-configuration))
    (description "Run the dnsmasq DNS server.")))
+
+\f
+;;;
+;;; 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 ddclient.conf file.")
+  (extra-options
+   (list '())
+   "Extra options will be appended to ddclient configuration 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))
-- 
2.18.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [bug#32141] [PATCH] services: Add ddclient service.
  2018-08-01 17:27       ` Oleg Pykhalov
@ 2018-08-27 11:22         ` Ludovic Courtès
  2018-08-29 22:45           ` bug#32141: " Oleg Pykhalov
  0 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2018-08-27 11:22 UTC (permalink / raw)
  To: Oleg Pykhalov; +Cc: 32141

Hi Oleg,

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

Oleg Pykhalov <go.wigust@gmail.com> skribis:

> I applied all your suggestions and updated the documentation.  The patch
> is attached below.  I run a ddclient service from this patch currently.

Neat.

> ludo@gnu.org (Ludovic Courtès) writes:

[...]

>> In short we must not manipulate secrets in anything that goes through
>> the store.  The only thing I can suggest is to leave it up to the
>> user to create a file containing the secret in an out-of-band fashion;
>> /etc is a good place for such things.
>>
>> For example, they could create /etc/ddclient-secrets and then we would
>> somehow arrange to get that file read.
>>
>> To do that there are two possibilities that come to mind:
>>
>>   1. If the config file syntax has an “include” directive, just include
>>      /etc/ddclient-secrets unconditionally in the generated config file.
>>
>>   2. Write an activation snippet that concatenates the generated config
>>      file with /etc/ddclient-secrets and stores that as
>>      /etc/ddclient.conf (or something like that.)
>>
>> Thoughts?
>
> Could we use ‘/etc/ddclient’ directory for secrets file, because
> ddclient program use this directory by default?

Sure.

> From 3f47ae60ecb2e8780c451e93976b5c83135d8420 Mon Sep 17 00:00:00 2001
> From: Oleg Pykhalov <go.wigust@gmail.com>
> Date: Fri, 13 Jul 2018 11:49:13 +0300
> Subject: [PATCH] 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.

[...]

> +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?

> +@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"}.

OK with changes along these lines.

Thank you!

Ludo’.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#32141: [PATCH] services: Add ddclient service.
  2018-08-27 11:22         ` Ludovic Courtès
@ 2018-08-29 22:45           ` Oleg Pykhalov
  0 siblings, 0 replies; 7+ messages in thread
From: Oleg Pykhalov @ 2018-08-29 22:45 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 32141-done

[-- Attachment #1: Type: text/plain, Size: 2010 bytes --]

Hi Ludovic,

ludo@gnu.org (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 <go.wigust@gmail.com> 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.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-08-29 22:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-13 14:58 [bug#32141] [PATCH] services: Add ddclient service Oleg Pykhalov
2018-07-19  9:40 ` Ludovic Courtès
2018-07-25  7:22   ` Oleg Pykhalov
2018-07-26  8:51     ` Ludovic Courtès
2018-08-01 17:27       ` Oleg Pykhalov
2018-08-27 11:22         ` Ludovic Courtès
2018-08-29 22:45           ` bug#32141: " Oleg Pykhalov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).