implement systemd socket activation
License: MIT Signed-off-by: Steven Allen <steven@stebalien.com>
Steven Allen committed
Sep 23, 2018 at 21:47 UTC
429c4b537ca1078ac2f7d3f02942758d193e0f1a
8 files changed
+172
-49
cmd/ipfs/daemon.go
+57
-49
@@ -15,6 +15,7 @@ import (
15
version "github.com/ipfs/go-ipfs"
16
config "github.com/ipfs/go-ipfs-config"
17
cserial "github.com/ipfs/go-ipfs-config/serialize"
18
+ sockets "github.com/ipfs/go-ipfs/cmd/ipfs/sockets"
19
utilmain "github.com/ipfs/go-ipfs/cmd/ipfs/util"
20
oldcmds "github.com/ipfs/go-ipfs/commands"
21
"github.com/ipfs/go-ipfs/core"
@@ -290,11 +291,6 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
291
// fail before we get to that. It can't hurt to close it twice.
292
defer repo.Close()
293
293
- cfg, err := cctx.GetConfig()
294
- if err != nil {
295
- return err
296
- }
297
-
294
offline, _ := req.Options[offlineKwd].(bool)
295
ipnsps, _ := req.Options[enableIPNSPubSubKwd].(bool)
296
pubsub, _ := req.Options[enablePubSubKwd].(bool)
@@ -404,14 +400,10 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
400
return err
401
}
402
407
- // construct http gateway - if it is set in the config
408
- var gwErrc <-chan error
409
- if len(cfg.Addresses.Gateway) > 0 {
410
- var err error
411
- gwErrc, err = serveHTTPGateway(req, cctx)
412
- if err != nil {
413
- return err
414
- }
403
+ // construct http gateway
404
+ gwErrc, err := serveHTTPGateway(req, cctx)
405
+ if err != nil {
406
+ return err
407
}
408
409
// initialize metrics collector
@@ -446,31 +438,40 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
438
return nil, fmt.Errorf("serveHTTPApi: GetConfig() failed: %s", err)
439
}
440
449
- apiAddrs := make([]string, 0, 2)
450
- apiAddr, _ := req.Options[commands.ApiOption].(string)
451
- if apiAddr == "" {
452
- apiAddrs = cfg.Addresses.API
453
- } else {
454
- apiAddrs = append(apiAddrs, apiAddr)
441
+ listeners, err := sockets.TakeSockets("io.ipfs.api")
442
+ if err != nil {
443
+ return nil, fmt.Errorf("serveHTTPGateway: socket activation failed: %s", err)
444
}
445
457
- listeners := make([]manet.Listener, 0, len(apiAddrs))
458
- for _, addr := range apiAddrs {
459
- apiMaddr, err := ma.NewMultiaddr(addr)
460
- if err != nil {
461
- return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", apiAddr, err)
446
+ if len(listeners) == 0 {
447
+ apiAddrs := make([]string, 0, 2)
448
+ apiAddr, _ := req.Options[commands.ApiOption].(string)
449
+ if apiAddr == "" {
450
+ apiAddrs = cfg.Addresses.API
451
+ } else {
452
+ apiAddrs = append(apiAddrs, apiAddr)
453
}
454
464
- apiLis, err := manet.Listen(apiMaddr)
465
- if err != nil {
466
- return nil, fmt.Errorf("serveHTTPApi: manet.Listen(%s) failed: %s", apiMaddr, err)
455
+ listeners := make([]manet.Listener, 0, len(apiAddrs))
456
+ for _, addr := range apiAddrs {
457
+ apiMaddr, err := ma.NewMultiaddr(addr)
458
+ if err != nil {
459
+ return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", apiAddr, err)
460
+ }
461
+
462
+ apiLis, err := manet.Listen(apiMaddr)
463
+ if err != nil {
464
+ return nil, fmt.Errorf("serveHTTPApi: manet.Listen(%s) failed: %s", apiMaddr, err)
465
+ }
466
+
467
+ listeners = append(listeners, apiLis)
468
}
469
+ }
470
471
+ for _, listener := range listeners {
472
// we might have listened to /tcp/0 - lets see what we are listing on
470
- apiMaddr = apiLis.Multiaddr()
471
- fmt.Printf("API server listening on %s\n", apiMaddr)
472
- fmt.Printf("WebUI: http://%s/webui\n", apiLis.Addr())
473
- listeners = append(listeners, apiLis)
473
+ fmt.Printf("API server listening on %s\n", listener.Multiaddr())
474
+ fmt.Printf("WebUI: http://%s/webui\n", listener.Addr())
475
}
476
477
// by default, we don't let you load arbitrary ipfs objects through the api,
@@ -571,28 +572,35 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
572
writable = cfg.Gateway.Writable
573
}
574
574
- gatewayAddrs := cfg.Addresses.Gateway
575
- listeners := make([]manet.Listener, 0, len(gatewayAddrs))
576
- for _, addr := range gatewayAddrs {
577
- gatewayMaddr, err := ma.NewMultiaddr(addr)
578
- if err != nil {
579
- return nil, fmt.Errorf("serveHTTPGateway: invalid gateway address: %q (err: %s)", addr, err)
580
- }
575
+ listeners, err := sockets.TakeSockets("io.ipfs.gateway")
576
+ if err != nil {
577
+ return nil, fmt.Errorf("serveHTTPGateway: socket activation failed: %s", err)
578
+ }
579
582
- gwLis, err := manet.Listen(gatewayMaddr)
583
- if err != nil {
584
- return nil, fmt.Errorf("serveHTTPGateway: manet.Listen(%s) failed: %s", gatewayMaddr, err)
585
- }
586
- // we might have listened to /tcp/0 - lets see what we are listing on
587
- gatewayMaddr = gwLis.Multiaddr()
580
+ if len(listeners) == 0 {
581
+ gatewayAddrs := cfg.Addresses.Gateway
582
+ for _, addr := range gatewayAddrs {
583
+ gatewayMaddr, err := ma.NewMultiaddr(addr)
584
+ if err != nil {
585
+ return nil, fmt.Errorf("serveHTTPGateway: invalid gateway address: %q (err: %s)", addr, err)
586
+ }
587
589
- if writable {
590
- fmt.Printf("Gateway (writable) server listening on %s\n", gatewayMaddr)
591
- } else {
592
- fmt.Printf("Gateway (readonly) server listening on %s\n", gatewayMaddr)
588
+ gwLis, err := manet.Listen(gatewayMaddr)
589
+ if err != nil {
590
+ return nil, fmt.Errorf("serveHTTPGateway: manet.Listen(%s) failed: %s", gatewayMaddr, err)
591
+ }
592
+ listeners = append(listeners, gwLis)
593
}
594
+ }
595
+
596
+ // we might have listened to /tcp/0 - lets see what we are listing on
597
+ gwType := "readonly"
598
+ if writable {
599
+ gwType = "writable"
600
+ }
601
595
- listeners = append(listeners, gwLis)
602
+ for _, listener := range listeners {
603
+ fmt.Printf("Gateway (%s) server listening on %s\n", gwType, listener.Multiaddr())
604
}
605
606
cmdctx := *cctx
cmd/ipfs/sockets/sockets.go
new
+12
@@ -0,0 +1,12 @@
1
+// +build !linux
2
+
3
+package sockets
4
+
5
+import (
6
+ manet "github.com/multiformats/go-multiaddr-net"
7
+)
8
+
9
+// TakeSockets takes the sockets associated with the given name.
10
+func TakeSockets(name string) ([]manet.Listener, error) {
11
+ return nil, nil
12
+}
cmd/ipfs/sockets/sockets_linux.go
new
+61
@@ -0,0 +1,61 @@
1
+// +build linux
2
+
3
+package sockets
4
+
5
+import (
6
+ "net"
7
+ "sync"
8
+
9
+ activation "github.com/coreos/go-systemd/activation"
10
+ logging "github.com/ipfs/go-log"
11
+ manet "github.com/multiformats/go-multiaddr-net"
12
+)
13
+
14
+var log = logging.Logger("socket-activation")
15
+
16
+var socketsMu sync.Mutex
17
+var sockets map[string][]manet.Listener
18
+
19
+func initSockets() {
20
+ if sockets != nil {
21
+ return
22
+ }
23
+ nlisteners, err := activation.ListenersWithNames()
24
+ // Do this before checking the error. We need this to be non-nil so we
25
+ // don't try again.
26
+ sockets = make(map[string][]manet.Listener, len(nlisteners))
27
+ if err != nil {
28
+ log.Errorf("error parsing systemd sockets: %s", err)
29
+ return
30
+ }
31
+ for name, nls := range nlisteners {
32
+ mls := make([]manet.Listener, 0, len(nls))
33
+ for _, nl := range nls {
34
+ ml, err := manet.WrapNetListener(nl)
35
+ if err != nil {
36
+ log.Errorf("error converting a systemd-socket to a multiaddr listener: %s", err)
37
+ nl.Close()
38
+ continue
39
+ }
40
+ mls = append(mls, ml)
41
+ }
42
+ sockets[name] = mls
43
+ }
44
+}
45
+
46
+func mapListeners(nls []net.Listener) ([]manet.Listener, error) {
47
+ mls := make([]manet.Listener, len(nls))
48
+ return mls, nil
49
+}
50
+
51
+// TakeSockets takes the sockets associated with the given name.
52
+func TakeSockets(name string) ([]manet.Listener, error) {
53
+ socketsMu.Lock()
54
+ defer socketsMu.Unlock()
55
+ initSockets()
56
+
57
+ s := sockets[name]
58
+ delete(sockets, name)
59
+
60
+ return s, nil
61
+}
go.mod
+1
@@ -5,6 +5,7 @@ require (
5
github.com/AndreasBriese/bbloom v0.0.0-20190823232136-616930265c33 // indirect
6
github.com/blang/semver v3.5.1+incompatible
7
github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d
8
+ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
9
github.com/dustin/go-humanize v1.0.0
10
github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302
11
github.com/fatih/color v1.7.0 // indirect
go.sum
+2
@@ -51,6 +51,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
51
github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
52
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
53
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
54
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
55
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
56
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
57
github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=
58
github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=
misc/systemd/ipfs-api.socket
new
+15
@@ -0,0 +1,15 @@
1
+# Enabling this will *completely override* any API listeners configured in your
2
+# config.
3
+
4
+[Unit]
5
+Description=IPFS API Socket
6
+
7
+[Socket]
8
+Service=ipfs.service
9
+FileDescriptorName=io.ipfs.api
10
+BindIPv6Only=true
11
+ListenStream=127.0.0.1:5001
12
+ListenStream=[::1]:5001
13
+
14
+[Install]
15
+WantedBy=sockets.target
misc/systemd/ipfs-gateway.socket
new
+15
@@ -0,0 +1,15 @@
1
+# Enabling this will *completely override* any Gateway listeners configured in
2
+# your config.
3
+
4
+[Unit]
5
+Description=IPFS Gateway Socket
6
+
7
+[Socket]
8
+Service=ipfs.service
9
+FileDescriptorName=io.ipfs.gateway
10
+BindIPv6Only=true
11
+ListenStream=127.0.0.1:8080
12
+ListenStream=[::1]:8080
13
+
14
+[Install]
15
+WantedBy=sockets.target
misc/systemd/ipfs.service
new
+9
@@ -0,0 +1,9 @@
1
+[Unit]
2
+Description=IPFS Daemon
3
+
4
+[Service]
5
+ExecStart=/usr/bin/ipfs daemon --init --migrate
6
+KillSignal=SIGINT
7
+
8
+[Install]
9
+WantedBy=default.target