unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Ioannis Panagiotis Koutsidis <IXK680@student.bham.ac.uk>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guix-devel@gnu.org
Subject: Re: GSoC 2018 Syntax and semantics of systemd units in the Shepherd - 1st update
Date: Mon, 11 Jun 2018 15:07:23 +0300	[thread overview]
Message-ID: <9b3b976b-3a3f-d5b6-2aff-8200314f7b7a@student.bham.ac.uk> (raw)
In-Reply-To: <87zi01ilyh.fsf@gnu.org>

Thank you a lot for your comments! I will make sure to make the changes that you
suggested.

As for match and things like car/cdr, I had issues with match and signal handling
in the service file, which was why I changed it with a cond. As for the unit parser
I also take the rest of the list via cdar because match in something like
(x y rest ...) does not bind rest - I will probably have to use (x . (y . rest)) in
the replacement.

On 06/11/18 14:47, Ludovic Courtès wrote:
> Hello Ioannis!
> 
> Thanks for the update!
> 
> Ioannis Panagiotis Koutsidis <IXK680@student.bham.ac.uk> skribis:
> 
>> As the 1st phase is coming to an end I decided to post my progress. I have
>> implemented the unit file parsing as well as some of the basic entries supported
>> by it, such as ExecStart, User, Group, Restart, etc. In addition, support for
>> the systemd Restart values (on-success, on-failure, on-abnormal, and on-abort)
>> was added to the Shepherd via the restart-systemd field in the <service> class,
>> letting services written in guile to also use that feature.
> 
> Very nice!
> 
>> During the next phases I will focus on other common .service entries, .socket
>> support, as well as thoroughly testing the code.
> 
> Cool.  Adding unit tests like those currently under tests/ is definitely
> something you should do—you probably already run tests manually anyway,
> so it’s mostly a matter of putting them in a file.
> 
> For things like the unit file parser, you may find it more convenient to
> write the test in Scheme (currently all the tests are shell scripts.)
> That can easily be done by using the .scm file name extension for your
> test and then defining ‘SCM_LOG_COMPILER’ in Makefile.am.  If unsure,
> you can look at how Guix itself does it, or just stop by on #guix or ask
> on the list for details.
> 
> Some comments about the code:
> 
>>  From a0a46ead5e43cd2672a08adb4c16919c377514c2 Mon Sep 17 00:00:00 2001
>> From: Ioannis Panagiotis Koutsidis <ixk680@student.bham.ac.uk>
>> Date: Sat, 9 Jun 2018 16:17:27 +0300
>> Subject: [PATCH] Initial systemd unit support
> 
> Could you try to split it in several patches, where each patch
> represents a single “logical” change?
> 
> By that I mean that you could have a first patch that modifies ‘restart’
> and all in (shepherd service), possibly with extended tests to exercise
> the new functionality if appropriate.
> 
> A second patch would add the unit file parser in (shepherd systemd)
> along with its unit test.
> 
> For commit logs, please try to follow the ChangeLog convention:
> <https://www.gnu.org/prep/standards/html_node/Change-Logs.html>.  You
> can look at ‘git log’ and basically try to mimic what’s been done
> before.  Don’t lose your hair over commit logs though; it’s good to try
> to follow the conventions, but if you’re unsure or if you make mistakes,
> it’s not the end of the world.
> 
>> @@ -165,6 +166,11 @@ respawned, shows that it has been respawned more than TIMES in SECONDS."
>>     (respawn? #:init-keyword #:respawn?
>>   	    #:init-value #f
>>   	    #:getter respawn?)
>> +  ;; For the systemd restart values.  Can be 'no (when respawn? is #f),
>> +  ;; 'on-success, 'on-failure, 'on-abnormal, 'on-watchdog, 'on-abort, or 'always
>> +  (respawn-systemd #:init-keyword #:respawn-systemd
>> +                   #:init-value 'always
>> +                   #:getter respawn-systemd)
> 
> As briefly discussed on IRC, I think we should keep a single field for
> this.  So perhaps ‘respawn?’ must simply be renamed to ‘respawn’ (no
> question mark), with a comment like above explaining what the possible
> values are.
> 
>> +      (let* ([e (status:exit-val status)]
>> +             [t (status:term-sig status)]
>> +             [r (respawn-systemd serv)]
> 
> Please avoid square brackets to remain consistent with the rest of the
> code.  :-)
> 
>> +             [clean (or (zero?  e)
>> +                        (equal? t SIGHUP)
>> +                        (equal? t SIGINT)
>> +                        (equal? t SIGTERM)
>> +                        (equal? t SIGPIPE))])
> 
> Use ‘=’ rather than ‘equal?’ when we know we’re dealing with numbers.
> 
>> +        (if (or (equal? r 'always)
>> +                (equal? r 'on-watchdog) ;; not implemented yet
>> +                (and (equal? r 'on-success) clean)
>> +                (and (equal? r 'on-abnormal) (not clean) (equal? e #f))
>> +                (and (equal? r 'on-failure)  (not clean))
>> +                (and (equal? r 'on-abort)    (equal? t SIGABRT)))
> 
> Likewise, use ‘eq?’ for symbols.
> 
>> +++ b/modules/shepherd/systemd.scm
>> @@ -0,0 +1,143 @@
>> +;; systemd.scm -- Systemd support
>> +;; Copyright (C) 2018 Ioannis Panagiotis Koutsidis <gk.ppp7@gmail.com>
>> +;;
>> +;; This file is part of the GNU Shepherd.
>> +;;
>> +;; The GNU Shepherd is free software; you can redistribute it and/or modify it
>> +;; under the terms of the GNU General Public License as published by
>> +;; the Free Software Foundation; either version 3 of the License, or (at
>> +;; your option) any later version.
>> +;;
>> +;; The GNU Shepherd is distributed in the hope that it will be useful, but
>> +;; WITHOUT ANY WARRANTY; without even the implied warranty of
>> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +;; GNU General Public License for more details.
>> +;;
>> +;; You should have received a copy of the GNU General Public License
>> +;; along with the GNU Shepherd.  If not, see <http://www.gnu.org/licenses/>.
>> +
>> +(define-module (shepherd systemd)
>> +  #:use-module (ice-9 match)
>> +  #:use-module (ice-9 textual-ports)
>> +  #:use-module (oop goops)
>> +  #:use-module (shepherd service)
>> +  #:export (make-systemd-service))
>> +
>> +;; Change this
>> +(define unitdir "/systemd/")
> 
> I think we can remove it altogether.  :-)
> 
>> +;; Implements a state machine to parse the ini-like systemd unit files
>> +(define (unit-parse s)
> 
> Please turn the comment into a docstring.
> 
> Also, it may be more idiomatic to take an input port instead of a string
> as input.  As a result, you’ll have to call ‘read-char’ instead of
> traversing the list of characters, but otherwise the code should be
> pretty much the same.
> 
> How does that sound?
> 
> Also, I’d use the name ‘read-unit-file’ for this procedure, which is
> more inline with some naming conventions.
> 
>> +  (letrec ([unit-parse (lambda (s state key value kv)
>> +                         (match (list s state)
>> +                           [((or (#\newline _ ...)
>> +                                 ()) 'keypart)
>> +                            (error "Key " (list->string key) " is missing its value")]
>> +                           [(() (or 'valuepart 'firstchar 'ignoreline))
>> +                            kv]
>> +                           [lst (let ([rest (cdar lst)])
>> +                                  (match (list (caar lst) state)
>> +                                    [((or #\;
>> +                                          #\[) 'firstchar)
>> +                                     (unit-parse rest
>> +                                                 'ignoreline
>> +                                                 '()
>> +                                                 '()
>> +                                                 kv)]
>> +                                    [(#\newline (or 'firstchar
>> +                                                    'ignoreline))
>> +                                     (unit-parse rest
>> +                                                 'firstchar
>> +                                                 '()
>> +                                                 '()
>> +                                                 kv)]
>> +                                    [(#\= 'keypart)
>> +                                     (unit-parse rest
>> +                                                 'valuepart
>> +                                                 key
>> +                                                 '()
>> +                                                 kv)]
>> +                                    [(#\newline 'valuepart)
>> +                                     (unit-parse rest
>> +                                                 'firstchar
>> +                                                 '()
>> +                                                 '()
>> +                                                 `((,(list->string key)
>> +                                                    . ,(list->string value))
>> +                                                   . ,kv))]
>> +                                    [(_ 'ignoreline)
>> +                                     (unit-parse rest
>> +                                                 'ignoreline
>> +                                                 '()
>> +                                                 '()
>> +                                                 kv)]
>> +                                    [(c 'valuepart)
>> +                                     (unit-parse rest
>> +                                                 'valuepart
>> +                                                 key
>> +                                                 (append value `(,c))
>> +                                                 kv)]
>> +                                    [(c (or 'keypart 'firstchar))
>> +                                     (unit-parse rest
>> +                                                 'keypart
>> +                                                 (append key `(,c))
>> +                                                 '()
>> +                                                 kv)]))]))])
> 
> Instead of ‘letrec’, which leads to code that goes far to the right, you
> can use ‘define’ like this (it’s equivalent):
> 
>    (define (read-unit-file port)
>      (define (parse s state key value kv)
>        …)
>      (parse …))
> 
> Please always use ‘match’ instead of ‘car’, ‘cdr’, etc., and avoid
> abbreviations.  See
> <https://www.gnu.org/software/guix/manual/html_node/Coding-Style.html>,
> which mostly applies to the Shepherd as well.
> 
>> +(define (unit-parse-file path)
>> +  (let* ([in (open-input-file path)]
>> +         [out (unit-parse (get-string-all in))])
>> +    (close-port in)
>> +    out))
> 
> This will probably not be needed anymore (just like Scheme itself
> provides a ‘read’ procedure and no ‘read-file’ procedure.)
> 
>> +;; like assoc but uses a coninuation for failure and success
>> +(define (kassoc key alst failure success)
>> +  (let ((res (assoc key alst)))
>> +    (if (equal? res #f)
>> +        failure
>> +        (success (cdr res)))))
>> +
>> +;; like assoc but 1: allows the use of a default value on failure
>> +;; and 2: returns just the value instead of (cons key value)
>> +(define (dassoc key alst default)
>> +  (kassoc key alst default (lambda (x) x)))
> 
> Most likely these are not needed.  :-)
> 
>> +(define (make-systemd-service name)
> 
> Rather:
> 
>    (unit-file->service port)
> 
> ?
> 
>> +  (let* ([alst      (unit-parse-file (string-append unitdir name))]
>> +         [busname   (dassoc "BusName"   alst #f)]
>> +         [execstart (dassoc "ExecStart" alst #f)]
>> +         [type      (dassoc "Type"      alst (if (equal? execstart #f)
>> +                                                 "oneshot"
>> +                                                 (if (equal? busname #f)
>> +                                                     "simple"
>> +                                                     "dbus")))]
>> +         [restart         (string->symbol (dassoc "Restart" alst "no"))]
>> +         [user            (dassoc "User"             alst #f)]
>> +         [group           (dassoc "Group"            alst #f)]
>> +         [rootdir         (dassoc "RootDirectory"    alst "/")] ;; not currently used
>> +         [workdir         (dassoc "WorkingDirectory" alst rootdir)]
>> +         [command         execstart])
> 
> The (dassoc …) above can be replaced by:
> 
>    (assoc-ref alist "Thing")
> 
> or:
> 
>    (or (assoc-ref alist "Thing") 'default-thing)
> 
>> +(register-services (make-systemd-service "test.service"))
> 
> This should go to the unit test.
> 
> The unit parser looks “good enough”, so once you have a unit test for
> it, I’d suggest moving to implementing the semantics of unit files
> (which you’ve started a bit.)  You may find that some things, such as
> socket activation, are hard to implement in the current code.  At that
> point we can start discussing how to do that, which will probably mean
> moving using Fibers to handle events.
> 
> Thank you,
> Ludo’.
> 

  reply	other threads:[~2018-06-11 12:07 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-11  3:02 GSoC 2018 Syntax and semantics of systemd units in the Shepherd - 1st update Ioannis Panagiotis Koutsidis
2018-06-11 11:47 ` Ludovic Courtès
2018-06-11 12:07   ` Ioannis Panagiotis Koutsidis [this message]
2018-06-12 13:11     ` Ludovic Courtès
2018-06-25 10:47 ` Gábor Boskovits
2018-06-29 19:15   ` Ioannis Panagiotis Koutsidis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9b3b976b-3a3f-d5b6-2aff-8200314f7b7a@student.bham.ac.uk \
    --to=ixk680@student.bham.ac.uk \
    --cc=guix-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).