File: systemd.sh

package info (click to toggle)
shepherd 1.0.9-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,828 kB
  • sloc: lisp: 8,779; sh: 3,586; makefile: 290; ansic: 50
file content (153 lines) | stat: -rw-r--r-- 5,063 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# GNU Shepherd --- Test transient services.
# Copyright © 2022-2025 Ludovic Courtès <ludo@gnu.org>
#
# 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 <https://www.gnu.org/licenses/>.

shepherd --version
herd --version

socket="t-socket-$$"
conf="t-conf-$$"
log="t-log-$$"
pid="t-pid-$$"
service_socket_dir="t-service-socket-$$"
service_socket="$service_socket_dir/socket"

herd="herd -s $socket"

# Create the socket directory with permissions other than those specified in
# the endpoint.
mkdir -p "$service_socket_dir"
chmod 755 "$service_socket_dir"

trap "cat $log || true; rm -r $service_socket_dir $socket $conf $log;
      test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT

cat > "$conf" <<EOF
(define %command
  ;; Simple echo server.
  (quasiquote ("$GUILE" "-c"
    ,(object->string
      '(begin
         (use-modules (ice-9 match) (ice-9 rdelim))

         (setvbuf (current-output-port) 'line)
         (setvbuf (current-error-port) 'line)

         (display "starting\n")
         (unless (= (string->number (getenv "LISTEN_PID")) (getpid))
           (error "wrong pid!" (getenv "LISTEN_PID")))
         (unless (= (string->number (getenv "LISTEN_FDS")) 1)
           (error "wrong LISTEN_FDS!" (getenv "LISTEN_FDS")))
         (let ((sock (fdopen 3 "r+0")))
           (unless (zero? (logand O_NONBLOCK (fcntl sock F_GETFL)))
             (error "socket is non-blocking!" sock))
           (match (accept sock)
             ((connection . peer)
              (format #t "accepting connection from ~s~%" peer)
              (display "hello\n" connection)
              (display (read-line connection) connection)
              (newline connection)
              (display "done\n" connection)
              (display "exiting!\n")
              (close-port connection)
              (close-port sock)))))))))

(define %endpoints
  (list (endpoint (make-socket-address AF_UNIX "$service_socket")
                  #:socket-directory-permissions #o700)))

(register-services
 (list (service
	 '(test-systemd-unix)
	 #:start (make-systemd-constructor %command %endpoints)
	 #:stop  (make-systemd-destructor)
         #:respawn-delay 0  ;make the test slightly faster
	 #:respawn? #t)
       (service
	 '(test-systemd-unix-eager)
	 #:start (make-systemd-constructor %command %endpoints
					   #:lazy-start? #f)
	 #:stop  (make-systemd-destructor))))
EOF

rm -f "$pid"
shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" &

# Wait till it's ready.
while ! test -f "$pid" ; do sleep 0.3 ; done

shepherd_pid="`cat $pid`"

file_permissions ()
{
    "$GUILE" -c "(display (number->string (stat:perms (stat \"$1\")) 8))"
}

converse_with_echo_server ()
{
    "$GUILE" -c "(use-modules (ice-9 match) (ice-9 rdelim))
      (define address $1)
      (define sock (socket (sockaddr:fam address) SOCK_STREAM 0))
      (connect sock address)
      (match (read-line sock) (\"hello\" #t))
      (display \"bye\n\" sock)
      (match (read-line sock) (\"bye\" #t))
      (match (read-line sock) (\"done\" #t))"
}


$herd start test-systemd-unix
$herd status test-systemd-unix | grep running
test $($herd status | grep '\+' | wc -l) -eq 2

$herd status test-systemd-unix | grep "Systemd-style"
$herd status test-systemd-unix | grep "$service_socket"
$herd status test-systemd-unix | grep "Command: $GUILE.*begin.*LISTEN_PID"

test "$(file_permissions "$service_socket_dir")" = "700"
test "$(file_permissions "$service_socket")" = "666"

for i in $(seq 1 3)
do
    converse_with_echo_server \
	"(make-socket-address AF_UNIX \"$service_socket\")"

    # Wait until the service has been respawned.
    until $herd status test-systemd-unix | grep running
    do
	sleep 0.1
    done
done

$herd stop test-systemd-unix
if converse_with_echo_server "(make-socket-address AF_UNIX \"$service_socket\")"
then false; else true; fi

# Now test the eager systemd-style service.
$herd start test-systemd-unix-eager
$herd status test-systemd-unix-eager | grep running

# The process should soon be running, before we've tried to connect to it.
while ! $herd status test-systemd-unix-eager | grep -E "PID: [0-9]+"
do $herd status test-systemd-unix-eager; sleep 0.3; done

child_pid="$($herd status test-systemd-unix-eager | grep PID: \
   | sed '-es/.*PID: \([0-9]\+\)$/\1/g')"
kill -0 "$child_pid"
converse_with_echo_server "(make-socket-address AF_UNIX \"$service_socket\")"
while ! $herd status test-systemd-unix-eager | grep stopped
do sleep 0.3; done