all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Defining shepherd user services -- feedback desired
@ 2018-02-04  1:13 Alex ter Weele
  2018-02-05 11:03 ` Ludovic Courtès
  0 siblings, 1 reply; 3+ messages in thread
From: Alex ter Weele @ 2018-02-04  1:13 UTC (permalink / raw)
  To: guix-devel

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


Attached is a manifest file which allows a user to write a
shepherd-service like the following:

(define redshift-service
  (shepherd-service
   (provision '(redshift))
   (modules `((gnu packages xdisorg)
              ,@%default-modules))
   (start #~(make-forkexec-constructor
             (list (string-append #$redshift "/bin/redshift")
                   "-l" "50:4")))))

And transform it into a package:

(services->package (list redshift-service))

This allows it to be included in a user's profile. This unites the
definition of a service with its dependencies (redshift, in the example
above). A user would not have to install a package just to use it as a
service, nor would they have to hand-write a Shepherd configuration
file.

It may be desired to add services->package and my edited version of
shepherd-configuration-file to Guix. I have not written a patch, though,
because I am unsure where it should go and some FIXMEs remain. Feedback
would be much appreciated!


[-- Attachment #2: user-services.scm --]
[-- Type: application/octet-stream, Size: 5217 bytes --]

(use-modules (srfi srfi-1)
             (gnu packages)
             (gnu packages emacs)
             (gnu packages xdisorg)
             (gnu services shepherd)
             (guix build-system trivial)
             (guix gexp)
             (guix monads)
             (guix packages)
             (guix store)
             (guix profiles))

;; a user writes services like this
(define emacs-service
  (shepherd-service
   (provision '(emacs))
   (modules `((gnu packages emacs)
              ,@%default-modules))
   (start #~(make-forkexec-constructor
             (list (string-append #$emacs "/bin/emacs")
                   ;;#;"--daemon"
                   ;; Why not --daemon? That causes emacs to fork and
                   ;; exit, so shepherd tries to restart it.
                   "--eval" "(server-start)"
                   ;; also doesn't work. spawns a window.
                   )))))

;; Based on Mathieu's service
(define redshift-service
  (shepherd-service
   (provision '(redshift))
   (modules `((gnu packages xdisorg)
              ,@%default-modules))
   ;; Why doesn't a with-imported-modules work here?
   (start #~(make-forkexec-constructor
             (list (string-append #$redshift "/bin/redshift")
                   "-l" "50:4")))))

;; the next two are copied from (gnu services shepherd) because:

;; * (gnu services shepherd)'s version of shepherd-configuration-file
;; is for the pid1 shepherd and has some stuff like fallback-to-REPL
;; that is not necessary for user services.

;; * (gnu services shepherd) doesn't export
;; shepherd-configuration-file.
(define (shepherd-service-file service)
  "Return a file defining SERVICE."
  (scheme-file
   "shepherd-service.scm"
   (with-imported-modules
    '((guix build utils)
      (guix build syscalls))
    #~(begin
        (use-modules #$@(shepherd-service-modules service))
        (make <service>
          #:docstring '#$(shepherd-service-documentation service)
          #:provides '#$(shepherd-service-provision service)
          #:requires '#$(shepherd-service-requirement service)
          #:respawn? '#$(shepherd-service-respawn? service)
          #:start #$(shepherd-service-start service)
          #:stop #$(shepherd-service-stop service))))))
(define (shepherd-configuration-file services)
  "Return the shepherd configuration file for SERVICES."
  ;; also not exported. Don't make a circular dependency.
  ;;(assert-valid-graph services)
  (define files (map shepherd-service-file services))
  (define config
    #~(begin
        (use-modules (srfi srfi-34))
        (apply register-services (map primitive-load '#$files))
        (for-each (lambda (service)
                    ;; In the Shepherd 0.3 the 'start' method can raise
                    ;; '&action-runtime-error' if it fails, so protect
                    ;; against it.  (XXX: 'action-runtime-error?' is not
                    ;; exported is 0.3, hence 'service-error?'.)
                    (guard (c ((service-error? c)
                               (format (current-error-port)
                                       "failed to start service '~a'~%"
                                       service)))
                      (start service)))
                  '#$(append-map shepherd-service-provision
                                 (filter shepherd-service-auto-start?
                                         services)))))
  (scheme-file "shepherd.conf" config))

(define (services->package services)
  "Yield a package for SERVICES by making them into a shepherd
configuration file via scheme-file."
  (package
   (name "shepherd-services")
   (version "0")
   (source (shepherd-configuration-file services))
   (build-system trivial-build-system)
   (arguments
     `(#:modules ((guix build utils))
       #:builder
       (begin
         (use-modules (guix build utils))
         (let ((install-directory (string-append %output "/etc/shepherd/")))
           (mkdir-p install-directory)
           (copy-file (assoc-ref %build-inputs "source")
                      (string-append install-directory "init.scm"))))))
   (synopsis "Package closing over Shepherd services.")
   (description (format #f "Contains services ~a"
                        (map shepherd-service-provision services)))
   (license #f
            ;; FIXME: should the licenses be the union of the services
            ;; closed over? What's the liccense of auto-generated code
            ;; anyway?
            )
   (home-page #f)))

(define manifest
  (packages->manifest
   (cons*
    (services->package (list redshift-service))
    (map
     specification->package
     '("emacs"                          ; emacs and supporting
                                        ; packages
       "magit"
       "emacs-guix"
       "emacs-debbugs"
       "emacs-evil"
       "geiser"
       "emacs-paredit"
       "emacs-erc-hl-nicks"
       "emacs-helm"
       "emacs-elfeed"
       "emacs-auctex"
       "emacs-pdf-tools"
       "emacs-tuareg"
       "emacs-org"
       "font-inconsolata"             ; preferred monospace font

       ;; other development
       "git"
       "openssh"                      ; for the client
       "stow"

       "icecat")))))

manifest

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

* Re: Defining shepherd user services -- feedback desired
  2018-02-04  1:13 Defining shepherd user services -- feedback desired Alex ter Weele
@ 2018-02-05 11:03 ` Ludovic Courtès
  2018-02-11  1:29   ` Chris Marusich
  0 siblings, 1 reply; 3+ messages in thread
From: Ludovic Courtès @ 2018-02-05 11:03 UTC (permalink / raw)
  To: Alex ter Weele; +Cc: guix-devel

Hey Alex,

Alex ter Weele <alex.ter.weele@gmail.com> skribis:

> Attached is a manifest file which allows a user to write a
> shepherd-service like the following:
>
> (define redshift-service
>   (shepherd-service
>    (provision '(redshift))
>    (modules `((gnu packages xdisorg)
>               ,@%default-modules))
>    (start #~(make-forkexec-constructor
>              (list (string-append #$redshift "/bin/redshift")
>                    "-l" "50:4")))))
>
> And transform it into a package:
>
> (services->package (list redshift-service))
>
> This allows it to be included in a user's profile. This unites the
> definition of a service with its dependencies (redshift, in the example
> above). A user would not have to install a package just to use it as a
> service, nor would they have to hand-write a Shepherd configuration
> file.

Indeed, that’s a neat hack!  And it ties software and service
deployment, which is great.

> ;; the next two are copied from (gnu services shepherd) because:
>
> ;; * (gnu services shepherd)'s version of shepherd-configuration-file
> ;; is for the pid1 shepherd and has some stuff like fallback-to-REPL
> ;; that is not necessary for user services.
>
> ;; * (gnu services shepherd) doesn't export
> ;; shepherd-configuration-file.

That we can fix.  :-)  Would it be enough for you?

I don’t think the first item is a showstopper, is it?

> (define (services->package services)
>   "Yield a package for SERVICES by making them into a shepherd
> configuration file via scheme-file."

This makes me think that perhaps we should generalize profile, and allow
non-package objects in there—it doesn’t feel right to define a <package>
for something that’s conceptually not a package at all.

But then that leads to issues, like what should ‘guix package -u’ do?
How should ~/.guix-profile/manifest represent these non-package things?
Should we add ‘guix package --install-service’ or similar?  (Well, that
may be overboard…)

It would be nice to think about whether/how we could make this part of
Guix proper.

Thanks!

Ludo’.

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

* Re: Defining shepherd user services -- feedback desired
  2018-02-05 11:03 ` Ludovic Courtès
@ 2018-02-11  1:29   ` Chris Marusich
  0 siblings, 0 replies; 3+ messages in thread
From: Chris Marusich @ 2018-02-11  1:29 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel, Alex ter Weele

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

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

>> (define (services->package services)
>>   "Yield a package for SERVICES by making them into a shepherd
>> configuration file via scheme-file."
>
> This makes me think that perhaps we should generalize profile, and allow
> non-package objects in there—it doesn’t feel right to define a <package>
> for something that’s conceptually not a package at all.
>
> But then that leads to issues, like what should ‘guix package -u’ do?
> How should ~/.guix-profile/manifest represent these non-package things?
> Should we add ‘guix package --install-service’ or similar?  (Well, that
> may be overboard…)

Profiles are our mechanism for "activating" simple software like GNU
Hello.  Software that does not need to be started, stopped, or otherwise
managed by a system like Shepherd.

What is a good mechanism for "activating" more complex software that
needs this sort of management?  Perhaps we can make a "guix service"
command which performs upgrades like we do in
'upgrade-shepherd-services' (from guix/scripts/system.scm), but arranges
to execute those commands against a user-specific Shepherd, not the root
user's Shepherd?  Perhaps a user profile should also have a "user
services activation script", like how an operating system declaration
has operating-system-activation-script (in gnu/system.scm)?

I personally wouldn't mind if this stuff (e.g., the service activation
script) wound up in a user's profile, but I can see what you're saying
about how it might make using manifests difficult.  So, I also wouldn't
mind if the user service activation stuff was stored somewhere else, for
example in ~/.guix-services".  Maybe we could we stash the activation
script into a place like ~/.guix-profile/boot, similar to how we store
an activation script for the entire system in /run/current-system/boot?
There must be a way to do this that makes sense...

-- 
Chris

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

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

end of thread, other threads:[~2018-02-11  1:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-04  1:13 Defining shepherd user services -- feedback desired Alex ter Weele
2018-02-05 11:03 ` Ludovic Courtès
2018-02-11  1:29   ` Chris Marusich

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.