Skip to content

Commit d2813ea

Browse files
authored
Merge pull request #151 from restic/add-socket-activation
Support running on demand via systemd
2 parents 32784a3 + f90205e commit d2813ea

File tree

8 files changed

+91
-8
lines changed

8 files changed

+91
-8
lines changed

changelog/unreleased/issue-126

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Feature: Allow running rest-server via systemd socket activation
2+
3+
We've added the option to have systemd create the listening socket and start the rest-server on demand.
4+
5+
https://github.com/restic/rest-server/issues/126
6+
https://github.com/restic/rest-server/pull/151
7+
https://github.com/restic/rest-server/pull/127

cmd/rest-server/listener_unix.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// +build !windows
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"log"
8+
"net"
9+
10+
"github.com/coreos/go-systemd/activation"
11+
)
12+
13+
// findListener tries to find a listener via systemd socket activation. If that
14+
// fails, it tries to create a listener on addr.
15+
func findListener(addr string) (listener net.Listener, err error) {
16+
// try systemd socket activation
17+
listeners, err := activation.Listeners()
18+
if err != nil {
19+
panic(err)
20+
}
21+
22+
switch len(listeners) {
23+
case 0:
24+
// no listeners found, listen manually
25+
listener, err = net.Listen("tcp", addr)
26+
if err != nil {
27+
return nil, fmt.Errorf("listen on %v failed: %w", addr, err)
28+
}
29+
30+
log.Printf("start server on %v", addr)
31+
return listener, nil
32+
33+
case 1:
34+
// one listener supplied by systemd, use that one
35+
//
36+
// for testing, run rest-server with systemd-socket-activate as follows:
37+
//
38+
// systemd-socket-activate -l 8080 ./rest-server
39+
log.Printf("systemd socket activation mode")
40+
return listeners[0], nil
41+
42+
default:
43+
return nil, fmt.Errorf("got %d listeners from systemd, expected one", len(listeners))
44+
}
45+
}

cmd/rest-server/listener_windows.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net"
7+
)
8+
9+
// findListener creates a listener.
10+
func findListener(addr string) (listener net.Listener, err error) {
11+
// listen manually
12+
listener, err = net.Listen("tcp", addr)
13+
if err != nil {
14+
return nil, fmt.Errorf("listen on %v failed: %w", addr, err)
15+
}
16+
17+
log.Printf("start server on %v", addr)
18+
return listener, nil
19+
}

cmd/rest-server/main.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,17 @@ func runRoot(cmd *cobra.Command, args []string) error {
129129
if err != nil {
130130
return err
131131
}
132+
133+
listener, err := findListener(server.Listen)
134+
if err != nil {
135+
return fmt.Errorf("unable to listen: %w", err)
136+
}
137+
132138
if !enabledTLS {
133-
log.Printf("Starting server on %s\n", server.Listen)
134-
err = http.ListenAndServe(server.Listen, handler)
139+
err = http.Serve(listener, handler)
135140
} else {
136-
137-
log.Println("TLS enabled")
138-
log.Printf("Private key: %s", privateKey)
139-
log.Printf("Public key(certificate): %s", publicKey)
140-
log.Printf("Starting server on %s\n", server.Listen)
141-
err = http.ListenAndServeTLS(server.Listen, publicKey, privateKey, handler)
141+
log.Printf("TLS enabled, private key %s, pubkey %v", privateKey, publicKey)
142+
err = http.ServeTLS(listener, handler, publicKey, privateKey)
142143
}
143144

144145
return err

examples/systemd/rest-server.service

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ Description=Rest Server
33
After=syslog.target
44
After=network.target
55

6+
# if you want to use socket activation, make sure to require the socket here
7+
#Requires=rest-server.socket
8+
69
[Service]
710
Type=simple
811
# You may prefer to use a different user or group on your system.

examples/systemd/rest-server.socket

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[Socket]
2+
ListenStream = 8080
3+
4+
[Install]
5+
WantedBy = sockets.target

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/restic/rest-server
33
go 1.14
44

55
require (
6+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
67
github.com/felixge/httpsnoop v1.0.2 // indirect
78
github.com/gorilla/handlers v1.5.1
89
github.com/miolini/datacounter v1.0.2

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
6565
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
6666
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
6767
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
68+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
69+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
6870
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
6971
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
7072
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

0 commit comments

Comments
 (0)