diff mbox series

[bug#54986,v2,3/3,WIP] services: mpd: Support socket activation.

Message ID 155723efbcf08c6e0bb6552b8f6341d4a1f20ecb.camel@gmail.com
State New
Headers show
Series [bug#54986] gnu: mpd: Add support for socket activation. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Liliana Marie Prikler April 23, 2022, 2:39 p.m. UTC
* gnu/services/audio.scm (<mpd-configuration>)[shepherd-endpoints]: New field.
(mpd-shepherd-service): Use it.
* doc/guix.texi (Music Player Daemon): Document it.
---
 doc/guix.texi          |  7 +++++++
 gnu/services/audio.scm | 45 ++++++++++++++++++++++++++++++------------
 2 files changed, 39 insertions(+), 13 deletions(-)

Comments

M April 23, 2022, 5:31 p.m. UTC | #1
> +(define (shepherd-endpoint->sexp endpoint)
> +  (match endpoint
> +    (($ <shepherd-endpoint> address
> +                            name style backlog socket-owner socket-
group
> +                            socket-directory-permissions)
> +     `(endpoint
> +       ,(match (sockaddr:fam address)
> +          ((? (cute = <> AF_INET) _)
> +           `(make-socket-addr AF_INET
> +                              ,(sockaddr:addr address)
> +                              ,(sockaddr:port address)))

Liliana Marie Prikler schreef op za 23-04-2022 om 16:39 [+0200]:
> +                 (list #$@(map shepherd-endpoint->sexp
> +                               (mpd-configuration-shepherd-endpoints config))) 

For hygiene reasons, should 'shepherd-endpoint->sexp' use @?

  `((@ (the module) endpoint)
    ,(match [...]
        ((@ [...] make-socket-addr (@ [...] AF_UNIX) ...)
        ...))

That way, no assumptions are made on what modules are imported and it
avoids hygiene problems like in

  ;; There are two ‘endpoints’ here: the ‘API endpoint’,
  ;; and Shepherd endpoints.
  #~(let ((endpoint "http://localhost:1234/api"))
      (make-systemd-constructor
         (list #$(file-append soft "/bin/ware")
               "--endpoint" #$endpoint)
         (list (shepherd-endpoint->sexp ...))))

Greetings,
Maxime.
M April 23, 2022, 5:35 p.m. UTC | #2
Liliana Marie Prikler schreef op za 23-04-2022 om 16:39 [+0200]:
> +@item @code{shepherd-endpoints} (default: @code{'()})
> +The endpoints shepherd shall bind and spawn MPD from.  If this field is
> +not empty (checked via @code{null?}), a systemd-style service is used
> +rather than a forkexec-service.

systemd-style / forkexec-service looks like an implementation detail to
me, not something useful to the user.

>  This delays the start of MPD until the
> +first client connects.
> 

Likewise.

>   As a side effect @code{port} and @code{address}
> +may be ignored.

Could these three fields be unified, keeping 'port' and 'address' only
for some backwards compatibility?  E.g.:

  (mpd-configuration
    (endpoints (list (shepherd-endpoint [a AF_INET6 address])
                     (shepherd-endpoint [a AF_UNIX address]))))

Greetings,
Maxime.
Liliana Marie Prikler April 23, 2022, 6:28 p.m. UTC | #3
Am Samstag, dem 23.04.2022 um 19:35 +0200 schrieb Maxime Devos:
> Liliana Marie Prikler schreef op za 23-04-2022 om 16:39 [+0200]:
> > +@item @code{shepherd-endpoints} (default: @code{'()})
> > +The endpoints shepherd shall bind and spawn MPD from.  If this
> > field is
> > +not empty (checked via @code{null?}), a systemd-style service is
> > used
> > +rather than a forkexec-service.
> 
> systemd-style / forkexec-service looks like an implementation detail
> to me, not something useful to the user.
> 
> >  This delays the start of MPD until the
> > +first client connects.
> 
> Likewise.
Even if this was just an implementation detail, I shall point to
Hyrum's law.

> >   As a side effect @code{port} and @code{address}
> > +may be ignored.
> 
> Could these three fields be unified, keeping 'port' and 'address'
> only for some backwards compatibility?  E.g.:
> 
>   (mpd-configuration
>     (endpoints (list (shepherd-endpoint [a AF_INET6 address])
>                      (shepherd-endpoint [a AF_UNIX address]))))
Not AFAIK.  MPD is less strict than Guile when it comes to addresses,
so converting from address+port to socket addresses is nontrivial. 
That being said, I'm not sure if they are even ignored.  MPD only warns
about pid_file, so they might also be used.

Cheers
Liliana Marie Prikler April 23, 2022, 6:36 p.m. UTC | #4
Am Samstag, dem 23.04.2022 um 19:31 +0200 schrieb Maxime Devos:
> > +(define (shepherd-endpoint->sexp endpoint)
> > +  (match endpoint
> > +    (($ <shepherd-endpoint> address
> > +                            name style backlog socket-owner
> > socket-
> group
> > +                            socket-directory-permissions)
> > +     `(endpoint
> > +       ,(match (sockaddr:fam address)
> > +          ((? (cute = <> AF_INET) _)
> > +           `(make-socket-addr AF_INET
> > +                              ,(sockaddr:addr address)
> > +                              ,(sockaddr:port address)))
> 
> Liliana Marie Prikler schreef op za 23-04-2022 om 16:39 [+0200]:
> > +                 (list #$@(map shepherd-endpoint->sexp
> > +                               (mpd-configuration-shepherd-
> > endpoints config))) 
> 
> For hygiene reasons, should 'shepherd-endpoint->sexp' use @?
> 
>   `((@ (the module) endpoint)
>     ,(match [...]
>         ((@ [...] make-socket-addr (@ [...] AF_UNIX) ...)
>         ...))
> 
> That way, no assumptions are made on what modules are imported and it
> avoids hygiene problems like in
> 
>   ;; There are two ‘endpoints’ here: the ‘API endpoint’,
>   ;; and Shepherd endpoints.
>   #~(let ((endpoint "http://localhost:1234/api"))
>       (make-systemd-constructor
>          (list #$(file-append soft "/bin/ware")
>                "--endpoint" #$endpoint)
>          (list (shepherd-endpoint->sexp ...))))
Good point, that's should probably done for defensive programming. 
Note also that I'm missing half of the documentation still, so it won't
be pushed too soon, though.
Ludovic Courtès April 27, 2022, 10:08 p.m. UTC | #5
Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:

> * gnu/services/audio.scm (<mpd-configuration>)[shepherd-endpoints]: New field.
> (mpd-shepherd-service): Use it.
> * doc/guix.texi (Music Player Daemon): Document it.

[...]

> +++ b/gnu/services/audio.scm
> @@ -78,6 +78,8 @@ (define-record-type* <mpd-configuration>
>                  (default "6600"))
>    (address      mpd-configuration-address
>                  (default "any"))
> +  (shepherd-endpoints mpd-configuration-shepherd-endpoints
> +                      (default '())) ; list of <shepherd-endpoint>

The way I see it, service configuration should be oblivious to whether
it’s started as “forkexec”, systemd, or inetd.

There’s already an ‘address’ field above, so my suggestion would be to
reuse it.  This is what I did for example for the openssh service, and
also for bitlbee and dicod here:

  https://issues.guix.gnu.org/54997#5

WDYT?

Thanks,
Ludo’.
Ludovic Courtès May 13, 2022, 3:55 p.m. UTC | #6
Hi Liliana,

What’s the status of this patch series?  Would be nice to have it in!

Ludo’.

Ludovic Courtès <ludo@gnu.org> skribis:

> Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:
>
>> * gnu/services/audio.scm (<mpd-configuration>)[shepherd-endpoints]: New field.
>> (mpd-shepherd-service): Use it.
>> * doc/guix.texi (Music Player Daemon): Document it.
>
> [...]
>
>> +++ b/gnu/services/audio.scm
>> @@ -78,6 +78,8 @@ (define-record-type* <mpd-configuration>
>>                  (default "6600"))
>>    (address      mpd-configuration-address
>>                  (default "any"))
>> +  (shepherd-endpoints mpd-configuration-shepherd-endpoints
>> +                      (default '())) ; list of <shepherd-endpoint>
>
> The way I see it, service configuration should be oblivious to whether
> it’s started as “forkexec”, systemd, or inetd.
>
> There’s already an ‘address’ field above, so my suggestion would be to
> reuse it.  This is what I did for example for the openssh service, and
> also for bitlbee and dicod here:
>
>   https://issues.guix.gnu.org/54997#5
>
> WDYT?
>
> Thanks,
> Ludo’.
Liliana Marie Prikler May 13, 2022, 5 p.m. UTC | #7
Am Freitag, dem 13.05.2022 um 17:55 +0200 schrieb Ludovic Courtès:
> Hi Liliana,
> 
> What’s the status of this patch series?  Would be nice to have it in!
The patch for MPD itself is good to go as far as I'm aware, the patch
for the service type is work in progress.

This question
> Ludovic Courtès <ludo@gnu.org> skribis:
> > The way I see it, service configuration should be oblivious to
> > whether it’s started as “forkexec”, systemd, or inetd.
has me in a bit of a bind in multiple ways.  For one, I don't see a
direct translation from MPD's configuration scheme to shepherd's.  For
another, the distinct semantics between forkexec and lazy loading cause
observable differences as in “What the fuck, I only ran mpc status, why
is the music now playing?” – this can be avoided if the user knows that
shepherd will be lazy-loading mpd and that it might as a result to
starting start playing on the first received command.

Moreover, I think the patch I added to make endpoint records
configurable from Guix could also serve to solve other bugs, e.g. SSH
only listening on IPv4 addresses, which would require us to be able to
specify whether to listen on IPv4, IPv6 or both through Guix.  Long
term, I think we should only keep the distinction between forkexec and
inetd/systemd for those services where it makes an observable
difference, like mpd.  For SSH, apart from bugs and perhaps people
using old shepherd, I don't think there'd be any reason to keep
forkexec beyond a certain point (in a future as distant as you would
want it to be).

Maxime also raised hygiene concerns that would be comparatively easy to
solve.

TL;DR: v2 [1/3] is good, [2/3 WIP] and [3/3 WIP] should be kept back
for now.

Cheers
diff mbox series

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 38aeda1d2d..6bfa854b1d 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -30883,6 +30883,13 @@  The port to run mpd on.
 The address that mpd will bind to.  To use a Unix domain socket,
 an absolute path can be specified here.
 
+@item @code{shepherd-endpoints} (default: @code{'()})
+The endpoints shepherd shall bind and spawn MPD from.  If this field is
+not empty (checked via @code{null?}), a systemd-style service is used
+rather than a forkexec-service.  This delays the start of MPD until the
+first client connects.  As a side effect @code{port} and @code{address}
+may be ignored.
+
 @item @code{outputs} (default: @code{"(list (mpd-output))"})
 The audio outputs that MPD can use.  By default this is a single output using pulseaudio.
 
diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
index c60053f33c..b184ac596a 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -78,6 +78,8 @@  (define-record-type* <mpd-configuration>
                 (default "6600"))
   (address      mpd-configuration-address
                 (default "any"))
+  (shepherd-endpoints mpd-configuration-shepherd-endpoints
+                      (default '())) ; list of <shepherd-endpoint>
   (outputs      mpd-configuration-outputs
                 (default (list (mpd-output)))))
 
@@ -140,19 +142,36 @@  (define (mpd-shepherd-service config)
    (documentation "Run the MPD (Music Player Daemon)")
    (requirement '(user-processes))
    (provision '(mpd))
-   (start #~(make-forkexec-constructor
-             (list #$(file-append mpd "/bin/mpd")
-                   "--no-daemon"
-                   #$(mpd-config->file config))
-             #:environment-variables
-             ;; Required to detect PulseAudio when run under a user account.
-             (list (string-append
-                    "XDG_RUNTIME_DIR=/run/user/"
-                    (number->string
-                     (passwd:uid
-                      (getpwnam #$(mpd-configuration-user config))))))
-             #:log-file #$(mpd-file-name config "log")))
-   (stop  #~(make-kill-destructor))))
+   (start (if (null? (mpd-configuration-shepherd-endpoints config))
+              #~(make-forkexec-constructor
+                 (list #$(file-append mpd "/bin/mpd")
+                       "--no-daemon"
+                       #$(mpd-config->file config))
+                 #:environment-variables
+                 ;; Required to detect PulseAudio when run under a user account.
+                 (list (string-append
+                        "XDG_RUNTIME_DIR=/run/user/"
+                        (number->string
+                         (passwd:uid
+                          (getpwnam #$(mpd-configuration-user config))))))
+                 #:log-file #$(mpd-file-name config "log"))
+              #~(make-systemd-constructor
+                 (list #$(file-append mpd "/bin/mpd")
+                       "--systemd"
+                       #$(mpd-config->file config))
+                 (list #$@(map shepherd-endpoint->sexp
+                               (mpd-configuration-shepherd-endpoints config)))
+                 #:environment-variables
+                 ;; Required to detect PulseAudio when run under a user account.
+                 (list (string-append
+                        "XDG_RUNTIME_DIR=/run/user/"
+                        (number->string
+                         (passwd:uid
+                          (getpwnam #$(mpd-configuration-user config))))))
+                 #:log-file #$(mpd-file-name config "log"))))
+   (stop  (if (null? (mpd-configuration-shepherd-endpoints config))
+              #~(make-kill-destructor)
+              #~(make-systemd-destructor)))))
 
 (define (mpd-service-activation config)
   (with-imported-modules '((guix build utils))