@cryptotaxi247 / kubo / commits / 0d428310b

feat(daemon): improve stdout on startup (#10472)

Marcin Rataj committed Aug 14, 2024 at 16:42 UTC 0d428310b28c663c473d684011780929b145d4f2
3 files changed +85 -38
cmd/ipfs/kubo/daemon.go
+46 -27
@@ -10,8 +10,10 @@ import (
10 "net/http"
11 _ "net/http/pprof"
12 "os"
13 + "regexp"
14 "runtime"
15 "sort"
16 + "strings"
17 "sync"
18 "time"
19
@@ -89,7 +91,7 @@ running, calls to 'ipfs' commands will be sent over the network to
91 the daemon.
92 `,
93 LongDescription: `
92 -The daemon will start listening on ports on the network, which are
94 +The Kubo daemon will start listening on ports on the network, which are
95 documented in (and can be modified through) 'ipfs config Addresses'.
96 For example, to change the 'Gateway' port:
97
@@ -109,11 +111,11 @@ other computers in the network, use 0.0.0.0 as the ip address:
111 Be careful if you expose the RPC API. It is a security risk, as anyone could
112 control your node remotely. If you need to control the node remotely,
113 make sure to protect the port as you would other services or database
112 -(firewall, authenticated proxy, etc).
114 +(firewall, authenticated proxy, etc), or at least set API.Authorizations.
115
116 HTTP Headers
117
116 -ipfs supports passing arbitrary headers to the RPC API and Gateway. You can
118 +Kubo supports passing arbitrary headers to the RPC API and Gateway. You can
119 do this by setting headers on the API.HTTPHeaders and Gateway.HTTPHeaders
120 keys:
121
@@ -124,7 +126,7 @@ Note that the value of the keys is an _array_ of strings. This is because
126 headers can have more than one value, and it is convenient to pass through
127 to other libraries.
128
127 -CORS Headers (for API)
129 +CORS Headers (for RPC API)
130
131 You can setup CORS headers the same way:
132
@@ -141,7 +143,7 @@ second signal.
143
144 IPFS_PATH environment variable
145
144 -ipfs uses a repository in the local file system. By default, the repo is
146 +Kubo uses a repository in the local file system. By default, the repo is
147 located at ~/.ipfs. To change the repo location, set the $IPFS_PATH
148 environment variable:
149
@@ -149,7 +151,7 @@ environment variable:
151
152 DEPRECATION NOTICE
153
152 -Previously, ipfs used an environment variable as seen below:
154 +Previously, Kubo used an environment variable as seen below:
155
156 export API_ORIGIN="http://localhost:8888/"
157
@@ -160,14 +162,14 @@ Headers.
162 },
163
164 Options: []cmds.Option{
163 - cmds.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized"),
165 + cmds.BoolOption(initOptionKwd, "Initialize Kubo with default settings if not already initialized"),
166 cmds.StringOption(initConfigOptionKwd, "Path to existing configuration file to be loaded during --init"),
167 cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"),
168 cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd),
169 cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"),
170 cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
171 cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
170 - cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"),
172 + cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow RPC API access to unlisted hashes"),
173 cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)"),
174 cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection"),
175 cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").WithDefault(true),
@@ -373,6 +375,8 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
375 return err
376 }
377
378 + fmt.Printf("PeerID: %s\n", cfg.Identity.PeerID)
379 +
380 if !psSet {
381 pubsub = cfg.Pubsub.Enabled.WithDefault(false)
382 }
@@ -463,7 +467,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
467 log.Fatal("Private network does not work with Routing.Type=auto. Update your config to Routing.Type=dht (or none, and do manual peering)")
468 }
469
466 - printSwarmAddrs(node)
470 + printLibp2pPorts(node)
471
472 if node.PrivateKey.Type() == p2pcrypto.RSA {
473 fmt.Print(`
@@ -563,7 +567,7 @@ take effect.
567 // Add ipfs version info to prometheus metrics
568 ipfsInfoMetric := promauto.NewGaugeVec(prometheus.GaugeOpts{
569 Name: "ipfs_info",
566 - Help: "IPFS version information.",
570 + Help: "Kubo IPFS version information.",
571 }, []string{"version", "commit"})
572
573 // Setting to 1 lets us multiply it with other stats to add the version labels
@@ -779,8 +783,8 @@ func rewriteMaddrToUseLocalhostIfItsAny(maddr ma.Multiaddr) ma.Multiaddr {
783 }
784 }
785
782 -// printSwarmAddrs prints the addresses of the host.
783 -func printSwarmAddrs(node *core.IpfsNode) {
786 +// printLibp2pPorts prints which ports are opened to facilitate swarm connectivity.
787 +func printLibp2pPorts(node *core.IpfsNode) {
788 if !node.IsOnline {
789 fmt.Println("Swarm not listening, running in offline mode.")
790 return
@@ -790,24 +794,39 @@ func printSwarmAddrs(node *core.IpfsNode) {
794 if err != nil {
795 log.Errorf("failed to read listening addresses: %s", err)
796 }
793 - lisAddrs := make([]string, len(ifaceAddrs))
794 - for i, addr := range ifaceAddrs {
795 - lisAddrs[i] = addr.String()
796 - }
797 - sort.Strings(lisAddrs)
798 - for _, addr := range lisAddrs {
799 - fmt.Printf("Swarm listening on %s\n", addr)
800 - }
797
802 - nodePhostAddrs := node.PeerHost.Addrs()
803 - addrs := make([]string, len(nodePhostAddrs))
804 - for i, addr := range nodePhostAddrs {
805 - addrs[i] = addr.String()
798 + // Multiple libp2p transports can use same port.
799 + // Deduplicate all listeners and collect unique IP:port (udp|tcp) combinations
800 + // which is useful information for operator deploying Kubo in TCP/IP infra.
801 + addrMap := make(map[string]map[string]struct{})
802 + re := regexp.MustCompile(`^/(?:ip[46]|dns(?:[46])?)/([^/]+)/(tcp|udp)/(\d+)(/.*)?$`)
803 + for _, addr := range ifaceAddrs {
804 + matches := re.FindStringSubmatch(addr.String())
805 + if matches != nil {
806 + hostname := matches[1]
807 + protocol := strings.ToUpper(matches[2])
808 + port := matches[3]
809 + var host string
810 + if matches[0][:4] == "/ip6" {
811 + host = fmt.Sprintf("[%s]:%s", hostname, port)
812 + } else {
813 + host = fmt.Sprintf("%s:%s", hostname, port)
814 + }
815 + if _, ok := addrMap[host]; !ok {
816 + addrMap[host] = make(map[string]struct{})
817 + }
818 + addrMap[host][protocol] = struct{}{}
819 + }
820 }
807 - sort.Strings(addrs)
808 - for _, addr := range addrs {
809 - fmt.Printf("Swarm announcing %s\n", addr)
821 + for host, protocolsSet := range addrMap {
822 + protocols := make([]string, 0, len(protocolsSet))
823 + for protocol := range protocolsSet {
824 + protocols = append(protocols, protocol)
825 + }
826 + sort.Strings(protocols)
827 + fmt.Printf("Swarm listening on %s (%s)\n", host, strings.Join(protocols, "+"))
828 }
829 + fmt.Printf("Run 'ipfs id' to inspect announced and discovered multiaddrs of this node.\n")
830 }
831
832 // serveHTTPGateway collects options, creates listener, prints status message and starts serving requests.
docs/changelogs/v0.30.md
+29
@@ -10,6 +10,7 @@
10 - [AutoNAT V2 Service Introduced Alongside V1](#autonat-v2-service-introduced-alongside-v1)
11 - [Automated `ipfs version check`](#automated-ipfs-version-check)
12 - [Version Suffix Configuration](#version-suffix-configuration)
13 + - [Cleaned Up `ipfs daemon` Startup Log](#cleaned-up-ipfs-daemon-startup-log)
14 - [📝 Changelog](#-changelog)
15 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
16
@@ -48,6 +49,34 @@ Defining the optional agent version suffix is now simpler. The [`Version.AgentSu
49
50 > [!NOTE]
51 > Setting a custom version suffix helps with ecosystem analysis, such as Amino DHT reports published at https://stats.ipfs.network
52 +>
53 +
54 +#### Cleaned Up `ipfs daemon` Startup Log
55 +
56 +The `ipfs daemon` startup output has been streamlined to enhance clarity and usability:
57 +
58 +```console
59 +$ ipfs daemon
60 +Initializing daemon...
61 +Kubo version: 0.30.0
62 +Repo version: 16
63 +System version: amd64/linux
64 +Golang version: go1.22.5
65 +PeerID: 12D3KooWQ73s1CQsm4jWwQvdCAtc5w8LatyQt7QLQARk5xdhK9CE
66 +Swarm listening on 127.0.0.1:4001 (TCP+UDP)
67 +Swarm listening on 192.0.2.10:4001 (TCP+UDP)
68 +Swarm listening on [::1]:4001 (TCP+UDP)
69 +Swarm listening on [2001:0db8::10]:4001 (TCP+UDP)
70 +Run 'ipfs id' to inspect announced and discovered multiaddrs of this node.
71 +RPC API server listening on /ip4/127.0.0.1/tcp/5001
72 +WebUI: http://127.0.0.1:5001/webui
73 +Gateway server listening on /ip4/127.0.0.1/tcp/8080
74 +Daemon is ready
75 +```
76 +
77 +The previous lengthy listing of all listener and announced multiaddrs has been removed due to its complexity, especially with modern libp2p nodes sharing multiple transports and long lists of `/webtransport` and `/webrtc-direct` certhashes.
78 +The output now features a simplified list of swarm listeners, displayed in the format `host:port (TCP+UDP)`, which provides essential information for debugging connectivity issues, particularly related to port forwarding.
79 +Announced libp2p addresses are no longer printed on startup, because libp2p may change or augument them based on AutoNAT, relay, and UPnP state. Instead, users are prompted to run `ipfs id` to obtain up-to-date list of listeners and announced multiaddrs in libp2p format.
80
81 ### 📝 Changelog
82
test/sharness/t0060-daemon.sh
+10 -11
@@ -76,17 +76,16 @@ test_expect_success "ipfs gateway works with the correct allowed origin port" '
76 curl -s -X POST -H "Origin:http://localhost:$GWAY_PORT" -I "http://$GWAY_ADDR/api/v0/version"
77 '
78
79 -test_expect_success "ipfs daemon output looks good" '
80 - STARTFILE="ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme" &&
81 - echo "Initializing daemon..." >expected_daemon &&
82 - ipfs version --all >> expected_daemon &&
83 - sed "s/^/Swarm listening on /" listen_addrs >>expected_daemon &&
84 - sed "s/^/Swarm announcing /" local_addrs >>expected_daemon &&
85 - echo "RPC API server listening on '$API_MADDR'" >>expected_daemon &&
86 - echo "WebUI: http://'$API_ADDR'/webui" >>expected_daemon &&
87 - echo "Gateway server listening on '$GWAY_MADDR'" >>expected_daemon &&
88 - echo "Daemon is ready" >>expected_daemon &&
89 - test_cmp expected_daemon actual_daemon
79 +test_expect_success "ipfs daemon output includes looks good" '
80 + test_should_contain "Initializing daemon..." actual_daemon &&
81 + test_should_contain "$(ipfs version --all)" actual_daemon &&
82 + test_should_contain "PeerID: $(ipfs config Identity.PeerID)" actual_daemon &&
83 + test_should_contain "Swarm listening on 127.0.0.1:" actual_daemon &&
84 + test_should_contain "RPC API server listening on '$API_MADDR'" actual_daemon &&
85 + test_should_contain "WebUI: http://'$API_ADDR'/webui" actual_daemon &&
86 + test_should_contain "Gateway server listening on '$GWAY_MADDR'" actual_daemon &&
87 + test_should_contain "Daemon is ready" actual_daemon &&
88 + cat actual_daemon
89 '
90
91 test_expect_success ".ipfs/ has been created" '