master
go 182 lines 4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package ipfs
4
5 import (
6 "fmt"
7
8 "github.com/netdata/netdata/go/plugins/pkg/web"
9 )
10
11 type (
12 ipfsStatsBw struct {
13 TotalIn int64 `json:"TotalIn"`
14 TotalOut int64 `json:"TotalOut"`
15 RateIn *float64 `json:"RateIn"`
16 RateOut *float64 `json:"RateOut"`
17 }
18 ipfsStatsRepo struct {
19 RepoSize int64 `json:"RepoSize"`
20 StorageMax int64 `json:"StorageMax"`
21 NumObjects int64 `json:"NumObjects"`
22 }
23 ipfsSwarmPeers struct {
24 Peers []any `json:"Peers"`
25 }
26 ipfsPinsLs struct {
27 Keys map[string]struct {
28 Type string `json:"type"`
29 } `json:"Keys"`
30 }
31 )
32
33 const (
34 urlPathStatsBandwidth = "/api/v0/stats/bw" // https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-stats-bw
35 urlPathStatsRepo = "/api/v0/stats/repo" // https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-stats-repo
36 urlPathSwarmPeers = "/api/v0/swarm/peers" // https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-swarm-peers
37 urlPathPinLs = "/api/v0/pin/ls" // https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-pin-ls
38 )
39
40 func (c *Collector) collect() (map[string]int64, error) {
41 mx := make(map[string]int64)
42
43 if err := c.collectStatsBandwidth(mx); err != nil {
44 return nil, err
45 }
46 if err := c.collectSwarmPeers(mx); err != nil {
47 return nil, err
48 }
49 if c.QueryRepoApi {
50 // https://github.com/netdata/netdata/pull/9687
51 // TODO: collect by default with "size-only"
52 // https://github.com/ipfs/kubo/issues/7528#issuecomment-657398332
53 if err := c.collectStatsRepo(mx); err != nil {
54 return nil, err
55 }
56 }
57 if c.QueryPinApi {
58 if err := c.collectPinLs(mx); err != nil {
59 return nil, err
60 }
61 }
62
63 return mx, nil
64 }
65
66 func (c *Collector) collectStatsBandwidth(mx map[string]int64) error {
67 stats, err := c.queryStatsBandwidth()
68 if err != nil {
69 return err
70 }
71
72 mx["in"] = stats.TotalIn
73 mx["out"] = stats.TotalOut
74
75 return nil
76 }
77
78 func (c *Collector) collectSwarmPeers(mx map[string]int64) error {
79 stats, err := c.querySwarmPeers()
80 if err != nil {
81 return err
82 }
83
84 mx["peers"] = int64(len(stats.Peers))
85
86 return nil
87 }
88
89 func (c *Collector) collectStatsRepo(mx map[string]int64) error {
90 stats, err := c.queryStatsRepo()
91 if err != nil {
92 return err
93 }
94
95 mx["used_percent"] = 0
96 if stats.StorageMax > 0 {
97 mx["used_percent"] = stats.RepoSize * 100 / stats.StorageMax
98 }
99 mx["size"] = stats.RepoSize
100 mx["objects"] = stats.NumObjects
101
102 return nil
103 }
104
105 func (c *Collector) collectPinLs(mx map[string]int64) error {
106 stats, err := c.queryPinLs()
107 if err != nil {
108 return err
109 }
110
111 var n int64
112 for _, v := range stats.Keys {
113 if v.Type == "recursive" {
114 n++
115 }
116 }
117
118 mx["pinned"] = int64(len(stats.Keys))
119 mx["recursive_pins"] = n
120
121 return nil
122 }
123
124 func (c *Collector) queryStatsBandwidth() (*ipfsStatsBw, error) {
125 req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathStatsBandwidth)
126 if err != nil {
127 return nil, err
128 }
129
130 var stats ipfsStatsBw
131 if err := web.DoHTTP(c.httpClient).RequestJSON(req, &stats); err != nil {
132 return nil, err
133 }
134
135 if stats.RateIn == nil || stats.RateOut == nil {
136 return nil, fmt.Errorf("unexpected response: not ipfs data")
137 }
138
139 return &stats, nil
140 }
141
142 func (c *Collector) querySwarmPeers() (*ipfsSwarmPeers, error) {
143 req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathSwarmPeers)
144 if err != nil {
145 return nil, err
146 }
147
148 var stats ipfsSwarmPeers
149 if err := web.DoHTTP(c.httpClient).RequestJSON(req, &stats); err != nil {
150 return nil, err
151 }
152
153 return &stats, nil
154 }
155
156 func (c *Collector) queryStatsRepo() (*ipfsStatsRepo, error) {
157 req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathStatsRepo)
158 if err != nil {
159 return nil, err
160 }
161
162 var stats ipfsStatsRepo
163 if err := web.DoHTTP(c.httpClient).RequestJSON(req, &stats); err != nil {
164 return nil, err
165 }
166
167 return &stats, nil
168 }
169
170 func (c *Collector) queryPinLs() (*ipfsPinsLs, error) {
171 req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathPinLs)
172 if err != nil {
173 return nil, err
174 }
175
176 var stats ipfsPinsLs
177 if err := web.DoHTTP(c.httpClient).RequestJSON(req, &stats); err != nil {
178 return nil, err
179 }
180
181 return &stats, nil
182 }