@cryptotaxi247 / kubo / commits / 429c4b537

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