@cryptotaxi247 / netdata-1 / commits / 32e26f249

Port Ceph collector to Go (#18582)

Co-authored-by: ilyam8 <ilya@netdata.cloud>

Fotis Voutsas committed Sep 27, 2024 at 14:13 UTC 32e26f24957b4346846f5e9a4857738d8d77c67a
24 files changed +5612 -2
src/go/plugin/go.d/README.md
+1
@@ -58,6 +58,7 @@ see the appropriate collector readme.
58 | [bind](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/bind) | ISC Bind |
59 | [boinc](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/boinc) | BOINC |
60 | [cassandra](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/cassandra) | Cassandra |
61 +| [ceph](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/ceph) | Ceph |
62 | [chrony](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/chrony) | Chrony |
63 | [clickhouse](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/clickhouse) | ClickHouse |
64 | [cockroachdb](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/cockroachdb) | CockroachDB |
src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go
-2
@@ -46,7 +46,6 @@ var prometheusPortAllocations = map[int]string{
46 9125: "statsd_exporter",
47 9126: "new_relic_exporter",
48 9127: "pgbouncer_exporter",
49 - 9128: "ceph_exporter",
49 9129: "haproxy_log_exporter",
50 9130: "unifi_poller",
51 9131: "varnish_exporter",
@@ -193,7 +192,6 @@ var prometheusPortAllocations = map[int]string{
192 9280: "citrix_netscaler_exporter",
193 9281: "fastd_exporter",
194 9282: "freeswitch_exporter",
196 - 9283: "ceph_ceph-mgr_prometheus_plugin",
195 9284: "gobetween",
196 9285: "database_exporter",
197 9286: "vdo_compression_and_deduplication_exporter",
src/go/plugin/go.d/config/go.d.conf
+1
@@ -23,6 +23,7 @@ modules:
23 # beanstalk: yes
24 # bind: yes
25 # boinc: yes
26 +# ceph: yes
27 # chrony: yes
28 # clickhouse: yes
29 # cockroachdb: yes
src/go/plugin/go.d/config/go.d/ceph.conf new
+6
@@ -0,0 +1,6 @@
1 +## All available configuration options, their descriptions and default values:
2 +## https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/ceph#readme
3 +
4 +#jobs:
5 +# - name: local
6 +# url: https://127.0.0.1:8443
src/go/plugin/go.d/config/go.d/sd/net_listeners.conf
+7
@@ -26,6 +26,8 @@ classify:
26 expr: '{{ and (eq .Port "8653") (eq .Comm "bind" "named") }}'
27 - tags: "cassandra"
28 expr: '{{ and (eq .Port "7072") (glob .Cmdline "*cassandra*") }}'
29 + - tags: "ceph"
30 + expr: '{{ and (eq .Port "8443") (eq .Comm "ceph-mgr") }}'
31 - tags: "chrony"
32 expr: '{{ and (eq .Port "323") (eq .Comm "chronyd") }}'
33 - tags: "clickhouse"
@@ -190,6 +192,11 @@ compose:
192 module: cassandra
193 name: local
194 url: http://{{.Address}}/metrics
195 + - selector: "ceph"
196 + template: |
197 + module: ceph
198 + name: local
199 + url: https://{{.Address}}
200 - selector: "chrony"
201 template: |
202 module: chrony
src/go/plugin/go.d/modules/ceph/api.go new
+126
@@ -0,0 +1,126 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "net/url"
7 +)
8 +
9 +// https://docs.ceph.com/en/reef/mgr/ceph_api/
10 +
11 +const (
12 + urlPathApiAuth = "/api/auth"
13 + urlPathApiAuthCheck = "/api/auth/check"
14 + urlPathApiAuthLogout = "/api/auth/logout"
15 + urlPathApiHealthMinimal = "/api/health/minimal"
16 + urlPathApiMonitor = "/api/monitor"
17 + urlPathApiOsd = "/api/osd"
18 + urlPathApiPool = "/api/pool"
19 +)
20 +
21 +var (
22 + urlQueryApiPool = url.Values{"stats": {"true"}}.Encode()
23 +)
24 +
25 +const (
26 + hdrAcceptVersion = "application/vnd.ceph.api.v1.0+json"
27 + hdrContentTypeJson = "application/json"
28 +)
29 +
30 +type apiHealthMinimalResponse struct {
31 + Health struct {
32 + Status string `json:"status"`
33 + } `json:"health"`
34 + MonStatus struct {
35 + MonMap struct {
36 + Mons []any `json:"mons"`
37 + } `json:"monmap"`
38 + } `json:"mon_status"`
39 + ScrubStatus string `json:"scrub_status"`
40 + OsdMap struct {
41 + Osds []struct {
42 + In int64 `json:"in"`
43 + Up int64 `json:"up"`
44 + } `json:"osds"`
45 + } `json:"osd_map"`
46 + PgInfo struct {
47 + ObjectStats struct {
48 + NumObjects int64 `json:"num_objects"`
49 + NumObjectsDegraded int64 `json:"num_objects_degraded"`
50 + NumObjectsMisplaced int64 `json:"num_objects_misplaced"`
51 + NumObjectsUnfound int64 `json:"num_objects_unfound"`
52 + } `json:"object_stats"`
53 + Statuses map[string]int64 `json:"statuses"`
54 + PgsPerOsd float64 `json:"pgs_per_osd"`
55 + } `json:"pg_info"`
56 + Pools []any `json:"pools"`
57 + MgrMap struct {
58 + ActiveName string `json:"active_name"`
59 + Standbys []struct {
60 + Gid int `json:"gid"`
61 + } `json:"standbys"`
62 + } `json:"mgr_map"`
63 + Df struct {
64 + Stats struct {
65 + TotalAvailBytes int64 `json:"total_avail_bytes"`
66 + TotalBytes int64 `json:"total_bytes"`
67 + TotalUsedRawBytes int64 `json:"total_used_raw_bytes"`
68 + } `json:"stats"`
69 + } `json:"df"`
70 + ClientPerf struct {
71 + ReadBytesSec float64 `json:"read_bytes_sec"`
72 + ReadOpPerSec float64 `json:"read_op_per_sec"`
73 + WriteBytesSec float64 `json:"write_bytes_sec"`
74 + WriteOpPerSec float64 `json:"write_op_per_sec"`
75 + RecoveringBytesPerSec float64 `json:"recovering_bytes_per_sec"`
76 + } `json:"client_perf"`
77 + Hosts int64 `json:"hosts"`
78 + Rgw int64 `json:"rgw"`
79 + IscsiDaemons struct {
80 + Up int64 `json:"up"`
81 + Down int64 `json:"down"`
82 + } `json:"iscsi_daemons"`
83 +}
84 +
85 +type apiOsdResponse struct {
86 + UUID string `json:"uuid"`
87 + ID int64 `json:"id"`
88 + Up int64 `json:"up"`
89 + In int64 `json:"in"`
90 + OsdStats struct {
91 + Statfs struct {
92 + Total int64 `json:"total"`
93 + Available int64 `json:"available"`
94 + } `json:"statfs"`
95 + PerfStat struct {
96 + CommitLatencyMs float64 `json:"commit_latency_ms"`
97 + ApplyLatencyMs float64 `json:"apply_latency_ms"`
98 + } `json:"perf_stat"`
99 + } `json:"osd_stats"`
100 + Stats struct {
101 + OpW float64 `json:"op_w"`
102 + OpInBytes float64 `json:"op_in_bytes"`
103 + OpR float64 `json:"op_r"`
104 + OpOutBytes float64 `json:"op_out_bytes"`
105 + } `json:"stats"`
106 + Tree struct {
107 + DeviceClass string `json:"device_class"`
108 + Type string `json:"type"`
109 + Name string `json:"name"`
110 + } `json:"tree"`
111 +}
112 +
113 +type apiPoolResponse struct {
114 + PoolName string `json:"pool_name"`
115 + Stats struct {
116 + Stored struct{ Latest float64 } `json:"stored"`
117 + Objects struct{ Latest float64 } `json:"objects"`
118 + AvailRaw struct{ Latest float64 } `json:"avail_raw"`
119 + BytesUsed struct{ Latest float64 } `json:"bytes_used"`
120 + PercentUsed struct{ Latest float64 } `json:"percent_used"`
121 + Reads struct{ Latest float64 } `json:"rd"`
122 + ReadBytes struct{ Latest float64 } `json:"rd_bytes"`
123 + Writes struct{ Latest float64 } `json:"wr"`
124 + WrittenBytes struct{ Latest float64 } `json:"wr_bytes"`
125 + } `json:"stats"`
126 +}
src/go/plugin/go.d/modules/ceph/auth.go new
+139
@@ -0,0 +1,139 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "bytes"
7 + "encoding/json"
8 + "errors"
9 + "io"
10 + "net/http"
11 + "net/url"
12 +
13 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
14 +)
15 +
16 +type (
17 + authLoginResp struct {
18 + Token string `json:"token"`
19 + }
20 + authCheckResp struct {
21 + Username string `json:"username"`
22 + Permissions map[string]any `json:"permissions"`
23 + }
24 +)
25 +
26 +func (c *Ceph) authLogin() (string, error) {
27 + // https://docs.ceph.com/en/reef/mgr/ceph_api/#post--api-auth
28 +
29 + req, err := func() (*http.Request, error) {
30 + var credentials = struct {
31 + Username string `json:"username"`
32 + Password string `json:"password"`
33 + }{
34 + Username: c.Username,
35 + Password: c.Password,
36 + }
37 +
38 + bs, err := json.Marshal(credentials)
39 + if err != nil {
40 + return nil, err
41 + }
42 +
43 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiAuth)
44 + if err != nil {
45 + return nil, err
46 + }
47 +
48 + body := bytes.NewReader(bs)
49 +
50 + req.Body = io.NopCloser(body)
51 + req.ContentLength = int64(body.Len())
52 + req.Method = http.MethodPost
53 + req.Header.Set("Accept", hdrAcceptVersion)
54 + req.Header.Set("Content-Type", hdrContentTypeJson)
55 +
56 + return req, nil
57 + }()
58 + if err != nil {
59 + return "", err
60 + }
61 +
62 + var tok authLoginResp
63 +
64 + if err := c.webClient(201).RequestJSON(req, &tok); err != nil {
65 + return "", err
66 + }
67 +
68 + if tok.Token == "" {
69 + return "", errors.New("empty token")
70 + }
71 +
72 + return tok.Token, nil
73 +}
74 +
75 +func (c *Ceph) authCheck() (bool, error) {
76 + // https://docs.ceph.com/en/reef/mgr/ceph_api/#post--api-auth-check
77 + if c.token == "" {
78 + return false, nil
79 + }
80 +
81 + req, err := func() (*http.Request, error) {
82 + bs, err := json.Marshal(authLoginResp{Token: c.token})
83 + if err != nil {
84 + return nil, err
85 + }
86 +
87 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiAuthCheck)
88 + if err != nil {
89 + return nil, err
90 + }
91 +
92 + body := bytes.NewReader(bs)
93 +
94 + req.Body = io.NopCloser(body)
95 + req.ContentLength = int64(body.Len())
96 + req.URL.RawQuery = url.Values{"token": {c.token}}.Encode() // TODO: it seems not necessary?
97 + req.Method = http.MethodPost
98 + req.Header.Set("Accept", hdrAcceptVersion)
99 + req.Header.Set("Content-Type", hdrContentTypeJson)
100 + return req, nil
101 + }()
102 + if err != nil {
103 + return false, err
104 + }
105 +
106 + var resp authCheckResp
107 +
108 + if err := c.webClient().RequestJSON(req, &resp); err != nil {
109 + return false, err
110 + }
111 +
112 + return resp.Username != "", nil
113 +}
114 +
115 +func (c *Ceph) authLogout() error {
116 + // https://docs.ceph.com/en/reef/mgr/ceph_api/#post--api-auth-logout
117 +
118 + if c.token == "" {
119 + return nil
120 + }
121 + defer func() { c.token = "" }()
122 +
123 + req, err := func() (*http.Request, error) {
124 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiAuthLogout)
125 + if err != nil {
126 + return nil, err
127 + }
128 +
129 + req.Method = http.MethodPost
130 + req.Header.Set("Accept", hdrAcceptVersion)
131 + req.Header.Set("Authorization", "Bearer "+c.token)
132 + return req, nil
133 + }()
134 + if err != nil {
135 + return err
136 + }
137 +
138 + return c.webClient().Request(req, nil)
139 +}
src/go/plugin/go.d/modules/ceph/ceph.go new
+132
@@ -0,0 +1,132 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + _ "embed"
7 + "errors"
8 + "fmt"
9 + "net/http"
10 + "sync"
11 + "time"
12 +
13 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
14 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/confopt"
15 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/tlscfg"
16 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
17 +)
18 +
19 +//go:embed "config_schema.json"
20 +var configSchema string
21 +
22 +func init() {
23 + module.Register("ceph", module.Creator{
24 + JobConfigSchema: configSchema,
25 + Defaults: module.Defaults{
26 + UpdateEvery: 10,
27 + },
28 + Create: func() module.Module { return New() },
29 + Config: func() any { return &Config{} },
30 + })
31 +}
32 +
33 +func New() *Ceph {
34 + return &Ceph{
35 + Config: Config{
36 + HTTPConfig: web.HTTPConfig{
37 + RequestConfig: web.RequestConfig{
38 + URL: "https://127.0.0.1:8443",
39 + },
40 + ClientConfig: web.ClientConfig{
41 + Timeout: confopt.Duration(time.Second * 2),
42 + TLSConfig: tlscfg.TLSConfig{
43 + InsecureSkipVerify: true,
44 + },
45 + },
46 + },
47 + },
48 + charts: &module.Charts{},
49 + seenPools: make(map[string]bool),
50 + seenOsds: make(map[string]bool),
51 + }
52 +}
53 +
54 +type Config struct {
55 + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
56 + web.HTTPConfig `yaml:",inline" json:""`
57 +}
58 +
59 +type Ceph struct {
60 + module.Base
61 + Config `yaml:",inline" json:""`
62 +
63 + charts *module.Charts
64 + addClusterChartsOnce sync.Once
65 +
66 + httpClient *http.Client
67 +
68 + token string
69 +
70 + fsid string // a unique identifier for the cluster
71 +
72 + seenPools map[string]bool
73 + seenOsds map[string]bool
74 +}
75 +
76 +func (c *Ceph) Configuration() any {
77 + return c.Config
78 +}
79 +
80 +func (c *Ceph) Init() error {
81 + if err := c.validateConfig(); err != nil {
82 + return fmt.Errorf("invalid config: %v", err)
83 + }
84 +
85 + httpClient, err := web.NewHTTPClient(c.ClientConfig)
86 + if err != nil {
87 + return err
88 + }
89 + c.httpClient = httpClient
90 +
91 + return nil
92 +}
93 +
94 +func (c *Ceph) Check() error {
95 + mx, err := c.collect()
96 + if err != nil {
97 + c.Error(err)
98 + return err
99 + }
100 +
101 + if len(mx) == 0 {
102 + return errors.New("no metrics collected")
103 + }
104 +
105 + return nil
106 +}
107 +
108 +func (c *Ceph) Charts() *module.Charts {
109 + return c.charts
110 +}
111 +
112 +func (c *Ceph) Collect() map[string]int64 {
113 + mx, err := c.collect()
114 + if err != nil {
115 + c.Error(err)
116 + }
117 +
118 + if len(mx) == 0 {
119 + return nil
120 + }
121 +
122 + return mx
123 +}
124 +
125 +func (c *Ceph) Cleanup() {
126 + if c.httpClient != nil {
127 + if err := c.authLogout(); err != nil {
128 + c.Warningf("failed to logout: %v", err)
129 + }
130 + c.httpClient.CloseIdleConnections()
131 + }
132 +}
src/go/plugin/go.d/modules/ceph/ceph_test.go new
+331
@@ -0,0 +1,331 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "bytes"
7 + "encoding/json"
8 + "io"
9 + "net/http"
10 + "net/http/httptest"
11 + "os"
12 + "sync/atomic"
13 + "testing"
14 +
15 + "github.com/stretchr/testify/assert"
16 +
17 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
18 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
19 +
20 + "github.com/stretchr/testify/require"
21 +)
22 +
23 +var (
24 + dataConfigJSON, _ = os.ReadFile("testdata/config.json")
25 + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
26 +
27 + dataVer16ApiHealthMinimal, _ = os.ReadFile("testdata/v16.2.15/api_health_minimal.json")
28 + dataVer16ApiOsd, _ = os.ReadFile("testdata/v16.2.15/api_osd.json")
29 + dataVer16ApiPoolStats, _ = os.ReadFile("testdata/v16.2.15/api_pool_stats.json")
30 + dataVer16ApiMonitor, _ = os.ReadFile("testdata/v16.2.15/api_monitor.json")
31 +)
32 +
33 +func Test_testDataIsValid(t *testing.T) {
34 + for name, data := range map[string][]byte{
35 + "dataConfigJSON": dataConfigJSON,
36 + "dataConfigYAML": dataConfigYAML,
37 + "dataVer16ApiHealthMinimal": dataVer16ApiHealthMinimal,
38 + "dataVer16ApiOsd": dataVer16ApiOsd,
39 + "dataVer16ApiPoolStats": dataVer16ApiPoolStats,
40 + "dataVer16ApiMonitor": dataVer16ApiMonitor,
41 + } {
42 + require.NotNil(t, data, name)
43 + }
44 +}
45 +
46 +func TestCeph_Configuration(t *testing.T) {
47 + module.TestConfigurationSerialize(t, &Ceph{}, dataConfigJSON, dataConfigYAML)
48 +}
49 +
50 +func TestCeph_Init(t *testing.T) {
51 + tesceph := map[string]struct {
52 + wantFail bool
53 + config Config
54 + }{
55 + "fails with default": {
56 + wantFail: true,
57 + config: New().Config,
58 + },
59 + "fail when URL not set": {
60 + wantFail: true,
61 + config: Config{
62 + HTTPConfig: web.HTTPConfig{
63 + RequestConfig: web.RequestConfig{URL: ""},
64 + },
65 + },
66 + },
67 + }
68 +
69 + for name, test := range tesceph {
70 + t.Run(name, func(t *testing.T) {
71 + ceph := New()
72 + ceph.Config = test.config
73 +
74 + if test.wantFail {
75 + assert.Error(t, ceph.Init())
76 + } else {
77 + assert.NoError(t, ceph.Init())
78 + }
79 + })
80 + }
81 +}
82 +
83 +func TestCeph_Check(t *testing.T) {
84 + tests := map[string]struct {
85 + wantFail bool
86 + prepare func(t *testing.T) (ceph *Ceph, cleanup func())
87 + }{
88 + "success with valid API key": {
89 + wantFail: false,
90 + prepare: caseOk,
91 + },
92 + "fail on connection refused": {
93 + wantFail: true,
94 + prepare: caseConnectionRefused,
95 + },
96 + "fail on 404 response": {
97 + wantFail: true,
98 + prepare: case404,
99 + },
100 + }
101 +
102 + for name, test := range tests {
103 + t.Run(name, func(t *testing.T) {
104 + ceph, cleanup := test.prepare(t)
105 + defer cleanup()
106 +
107 + if test.wantFail {
108 + assert.Error(t, ceph.Check())
109 + } else {
110 + assert.NoError(t, ceph.Check())
111 + }
112 + })
113 + }
114 +}
115 +
116 +func TestCeph_Charts(t *testing.T) {
117 + assert.NotNil(t, New().Charts())
118 +}
119 +
120 +func TestCeph_Collect(t *testing.T) {
121 + tests := map[string]struct {
122 + prepare func(t *testing.T) (ceph *Ceph, cleanup func())
123 + wantNumOfCharts int
124 + wantMetrics map[string]int64
125 + }{
126 + "success with valid API key": {
127 + prepare: caseOk,
128 + wantNumOfCharts: len(clusterCharts) + len(osdChartsTmpl)*2 + len(poolChartsTmpl)*2,
129 + wantMetrics: map[string]int64{
130 + "client_perf_read_bytes_sec": 1,
131 + "client_perf_read_op_per_sec": 1,
132 + "client_perf_recovering_bytes_per_sec": 1,
133 + "client_perf_write_bytes_sec": 1,
134 + "client_perf_write_op_per_sec": 1,
135 + "health_err": 0,
136 + "health_ok": 0,
137 + "health_warn": 1,
138 + "hosts_num": 1,
139 + "iscsi_daemons_down_num": 1,
140 + "iscsi_daemons_num": 2,
141 + "iscsi_daemons_up_num": 1,
142 + "mgr_active_num": 1,
143 + "mgr_standby_num": 1,
144 + "monitors_num": 1,
145 + "objects_degraded_num": 1,
146 + "objects_healthy_num": 3,
147 + "objects_misplaced_num": 1,
148 + "objects_num": 6,
149 + "objects_unfound_num": 1,
150 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_apply_latency_ms": 1,
151 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_commit_latency_ms": 1,
152 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_read_bytes": 1,
153 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_read_ops": 1,
154 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_size_bytes": 68715282432,
155 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_space_avail_bytes": 68410753024,
156 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_space_used_bytes": 304529408,
157 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_status_down": 0,
158 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_status_in": 1,
159 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_status_out": 0,
160 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_status_up": 1,
161 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_write_ops": 1,
162 + "osd_f5bbbe9d-e85b-419c-af5a-a57e2527cad3_written_bytes": 1,
163 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_apply_latency_ms": 1,
164 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_commit_latency_ms": 1,
165 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_read_bytes": 1,
166 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_read_ops": 1,
167 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_size_bytes": 107369988096,
168 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_space_avail_bytes": 107065458688,
169 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_space_used_bytes": 304529408,
170 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_status_down": 0,
171 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_status_in": 1,
172 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_status_out": 0,
173 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_status_up": 1,
174 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_write_ops": 1,
175 + "osd_f78537db-9b18-4c62-a24f-a4344fc28de7_written_bytes": 1,
176 + "osds_down_num": 0,
177 + "osds_in_num": 2,
178 + "osds_num": 2,
179 + "osds_out_num": 0,
180 + "osds_up_num": 2,
181 + "pg_status_category_clean": 1,
182 + "pg_status_category_unknown": 0,
183 + "pg_status_category_warning": 1,
184 + "pg_status_category_working": 0,
185 + "pgs_num": 2,
186 + "pgs_per_osd": 2,
187 + "pool_device_health_metrics_objects": 3,
188 + "pool_device_health_metrics_read_bytes": 1,
189 + "pool_device_health_metrics_read_ops": 1,
190 + "pool_device_health_metrics_size": 166530172973,
191 + "pool_device_health_metrics_space_avail_bytes": 166530172972,
192 + "pool_device_health_metrics_space_used_bytes": 1,
193 + "pool_device_health_metrics_space_utilization": 1000,
194 + "pool_device_health_metrics_write_ops": 3,
195 + "pool_device_health_metrics_written_bytes": 6144,
196 + "pool_mySuperPool_objects": 1,
197 + "pool_mySuperPool_read_bytes": 1,
198 + "pool_mySuperPool_read_ops": 1,
199 + "pool_mySuperPool_size": 166530172973,
200 + "pool_mySuperPool_space_avail_bytes": 166530172972,
201 + "pool_mySuperPool_space_used_bytes": 1,
202 + "pool_mySuperPool_space_utilization": 1000,
203 + "pool_mySuperPool_write_ops": 1,
204 + "pool_mySuperPool_written_bytes": 1,
205 + "pools_num": 2,
206 + "raw_capacity_avail_bytes": 175476178944,
207 + "raw_capacity_used_bytes": 609091584,
208 + "raw_capacity_utilization": 345,
209 + "rgw_num": 1,
210 + "scrub_status_active": 0,
211 + "scrub_status_disabled": 0,
212 + "scrub_status_inactive": 1,
213 + },
214 + },
215 + "fail on connection refused": {
216 + prepare: caseConnectionRefused,
217 + wantMetrics: nil,
218 + },
219 + "fail on 404 response": {
220 + prepare: case404,
221 + wantMetrics: nil,
222 + },
223 + }
224 +
225 + for name, test := range tests {
226 + t.Run(name, func(t *testing.T) {
227 + ceph, cleanup := test.prepare(t)
228 + defer cleanup()
229 +
230 + _ = ceph.Check()
231 +
232 + mx := ceph.Collect()
233 +
234 + require.Equal(t, test.wantMetrics, mx)
235 +
236 + if len(test.wantMetrics) > 0 {
237 + assert.Equal(t, test.wantNumOfCharts, len(*ceph.Charts()), "want charts")
238 +
239 + module.TestMetricsHasAllChartsDims(t, ceph.Charts(), mx)
240 + }
241 + })
242 + }
243 +}
244 +
245 +func caseOk(t *testing.T) (*Ceph, func()) {
246 + t.Helper()
247 +
248 + loginResp, _ := json.Marshal(authLoginResp{Token: "secret_token"})
249 + checkResp, _ := json.Marshal(authCheckResp{Username: "username"})
250 + var loggedIn atomic.Bool
251 +
252 + srv := httptest.NewServer(http.HandlerFunc(
253 + func(w http.ResponseWriter, r *http.Request) {
254 + switch r.Method {
255 + case http.MethodPost:
256 + switch r.URL.Path {
257 + case urlPathApiAuth:
258 + _, _ = w.Write(loginResp)
259 + w.WriteHeader(http.StatusCreated)
260 + loggedIn.Store(true)
261 + case urlPathApiAuthCheck:
262 + bs, _ := io.ReadAll(r.Body)
263 + if bytes.Equal(bs, loginResp) {
264 + _, _ = w.Write(checkResp)
265 + } else {
266 + w.WriteHeader(http.StatusNotFound)
267 + }
268 + case urlPathApiAuthLogout:
269 + w.WriteHeader(http.StatusOK)
270 + loggedIn.Store(false)
271 + default:
272 + w.WriteHeader(http.StatusNotFound)
273 + }
274 + case http.MethodGet:
275 + if !loggedIn.Load() {
276 + w.WriteHeader(http.StatusUnauthorized)
277 + return
278 + }
279 + switch r.URL.Path {
280 + case urlPathApiHealthMinimal:
281 + _, _ = w.Write(dataVer16ApiHealthMinimal)
282 + case urlPathApiOsd:
283 + _, _ = w.Write(dataVer16ApiOsd)
284 + case urlPathApiPool:
285 + if r.URL.RawQuery != urlQueryApiPool {
286 + w.WriteHeader(http.StatusNotFound)
287 + } else {
288 + _, _ = w.Write(dataVer16ApiPoolStats)
289 + }
290 + case urlPathApiMonitor:
291 + _, _ = w.Write(dataVer16ApiMonitor)
292 + default:
293 + w.WriteHeader(http.StatusNotFound)
294 + }
295 + }
296 + }))
297 +
298 + ceph := New()
299 + ceph.URL = srv.URL
300 + ceph.Username = "user"
301 + ceph.Password = "password"
302 + require.NoError(t, ceph.Init())
303 +
304 + return ceph, srv.Close
305 +}
306 +
307 +func caseConnectionRefused(t *testing.T) (*Ceph, func()) {
308 + t.Helper()
309 + ceph := New()
310 + ceph.URL = "http://127.0.0.1:65001"
311 + ceph.Username = "user"
312 + ceph.Password = "password"
313 + require.NoError(t, ceph.Init())
314 +
315 + return ceph, func() {}
316 +}
317 +
318 +func case404(t *testing.T) (*Ceph, func()) {
319 + t.Helper()
320 + srv := httptest.NewServer(http.HandlerFunc(
321 + func(w http.ResponseWriter, r *http.Request) {
322 + w.WriteHeader(http.StatusNotFound)
323 + }))
324 + ceph := New()
325 + ceph.URL = srv.URL
326 + ceph.Username = "user"
327 + ceph.Password = "password"
328 + require.NoError(t, ceph.Init())
329 +
330 + return ceph, srv.Close
331 +}
src/go/plugin/go.d/modules/ceph/charts.go new
+576
@@ -0,0 +1,576 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "fmt"
7 + "strings"
8 +
9 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
10 +)
11 +
12 +const (
13 + prioClusterStatus = module.Priority + iota
14 + prioClusterHostsCount
15 + prioClusterMonitorsCount
16 + prioClusterOSDsCount
17 + prioClusterOSDsByStatusCount
18 + prioClusterManagersCount
19 + prioClusterObjectGatewaysCount
20 + prioClusterIScsiGatewaysCount
21 + prioClusterIScsiGatewaysByStatusCount
22 +
23 + prioClusterPhysCapacityUtilization
24 + prioClusterPhysCapacityUsage
25 + prioClusterObjectsCount
26 + prioClusterObjectsByStatusPercent
27 + prioClusterPoolsCount
28 + prioClusterPGsCount
29 + prioClusterPGsByStatusCount
30 + prioClusterPGsPerOsdCount
31 +
32 + prioClusterClientIO
33 + prioClusterClientIOPS
34 + prioClusterClientRecoveryThroughput
35 + prioClusterScrubStatus
36 +
37 + prioOsdStatus
38 + prioOsdSpaceUsage
39 + prioOsdIO
40 + prioOsdIOPS
41 + prioOsdLatency
42 +
43 + prioPoolSpaceUtilization
44 + prioPoolSpaceUsage
45 + prioPoolObjectsCount
46 + prioPoolIO
47 + prioPoolIOPS
48 +)
49 +
50 +var clusterCharts = module.Charts{
51 + clusterStatusChart.Copy(),
52 + clusterHostsCountChart.Copy(),
53 + clusterMonitorsCountChart.Copy(),
54 + clusterOsdsCountChart.Copy(),
55 + clusterOsdsByStatusCountChart.Copy(),
56 + clusterManagersCountChart.Copy(),
57 + clusterObjectGatewaysCountChart.Copy(),
58 + clusterIScsiGatewaysCountChart.Copy(),
59 + clusterIScsiGatewaysByStatusCountChart.Copy(),
60 +
61 + clusterPhysCapacityUtilizationChart.Copy(),
62 + clusterPhysCapacityUsageChart.Copy(),
63 + clusterObjectsCountChart.Copy(),
64 + clusterObjectsByStatusPercentChart.Copy(),
65 + clusterPoolsCountChart.Copy(),
66 + clusterPGsCountChart.Copy(),
67 + clusterPGsByStatusCountChart.Copy(),
68 + clusterPgsPerOsdCountChart.Copy(),
69 +
70 + clusterClientIOChart.Copy(),
71 + clusterClientIOPSChart.Copy(),
72 + clusterRecoveryThroughputChart.Copy(),
73 + clusterScrubStatusChart.Copy(),
74 +}
75 +
76 +var osdChartsTmpl = module.Charts{
77 + osdStatusChartTmpl.Copy(),
78 + osdSpaceUsageChartTmpl.Copy(),
79 + osdIOChartTmpl.Copy(),
80 + osdIOPSChartTmpl.Copy(),
81 + osdLatencyChartTmpl.Copy(),
82 +}
83 +
84 +var poolChartsTmpl = module.Charts{
85 + poolSpaceUtilizationChartTmpl.Copy(),
86 + poolSpaceUsageChartTmpl.Copy(),
87 + poolObjectsCountChartTmpl.Copy(),
88 + poolIOChartTmpl.Copy(),
89 + poolIOPSChartTmpl.Copy(),
90 +}
91 +
92 +var (
93 + clusterStatusChart = module.Chart{
94 + ID: "cluster_status",
95 + Title: "Ceph Cluster Status",
96 + Fam: "status",
97 + Units: "status",
98 + Ctx: "ceph.cluster_status",
99 + Type: module.Line,
100 + Priority: prioClusterStatus,
101 + Dims: module.Dims{
102 + {ID: "health_ok", Name: "ok"},
103 + {ID: "health_err", Name: "err"},
104 + {ID: "health_warn", Name: "warn"},
105 + },
106 + }
107 + clusterHostsCountChart = module.Chart{
108 + ID: "cluster_hosts_count",
109 + Title: "Ceph Cluster Hosts",
110 + Fam: "status",
111 + Units: "hosts",
112 + Ctx: "ceph.cluster_hosts_count",
113 + Type: module.Line,
114 + Priority: prioClusterHostsCount,
115 + Dims: module.Dims{
116 + {ID: "hosts_num", Name: "hosts"},
117 + },
118 + }
119 + clusterMonitorsCountChart = module.Chart{
120 + ID: "cluster_monitors_count",
121 + Title: "Ceph Cluster Monitors",
122 + Fam: "status",
123 + Units: "monitors",
124 + Ctx: "ceph.cluster_monitors_count",
125 + Type: module.Line,
126 + Priority: prioClusterMonitorsCount,
127 + Dims: module.Dims{
128 + {ID: "monitors_num", Name: "monitors"},
129 + },
130 + }
131 + clusterOsdsCountChart = module.Chart{
132 + ID: "cluster_osds_count",
133 + Title: "Ceph Cluster OSDs",
134 + Fam: "status",
135 + Units: "osds",
136 + Ctx: "ceph.cluster_osds_count",
137 + Type: module.Line,
138 + Priority: prioClusterOSDsCount,
139 + Dims: module.Dims{
140 + {ID: "osds_num", Name: "osds"},
141 + },
142 + }
143 + clusterOsdsByStatusCountChart = module.Chart{
144 + ID: "cluster_osds_by_status_count",
145 + Title: "Ceph Cluster OSDs by Status",
146 + Fam: "status",
147 + Units: "osds",
148 + Ctx: "ceph.cluster_osds_by_status_count",
149 + Type: module.Line,
150 + Priority: prioClusterOSDsByStatusCount,
151 + Dims: module.Dims{
152 + {ID: "osds_up_num", Name: "up"},
153 + {ID: "osds_down_num", Name: "down"},
154 + {ID: "osds_in_num", Name: "in"},
155 + {ID: "osds_out_num", Name: "out"},
156 + },
157 + }
158 + clusterManagersCountChart = module.Chart{
159 + ID: "cluster_managers_count",
160 + Title: "Ceph Cluster Managers",
161 + Fam: "status",
162 + Units: "managers",
163 + Ctx: "ceph.cluster_managers_count",
164 + Type: module.Line,
165 + Priority: prioClusterManagersCount,
166 + Dims: module.Dims{
167 + {ID: "mgr_active_num", Name: "active"},
168 + {ID: "mgr_standby_num", Name: "standby"},
169 + },
170 + }
171 + clusterObjectGatewaysCountChart = module.Chart{
172 + ID: "cluster_object_gateways_count",
173 + Title: "Ceph Cluster Object Gateways (RGW)",
174 + Fam: "status",
175 + Units: "gateways",
176 + Ctx: "ceph.cluster_object_gateways_count",
177 + Type: module.Line,
178 + Priority: prioClusterObjectGatewaysCount,
179 + Dims: module.Dims{
180 + {ID: "rgw_num", Name: "object"},
181 + },
182 + }
183 + clusterIScsiGatewaysCountChart = module.Chart{
184 + ID: "cluster_iscsi_gateways_count",
185 + Title: "Ceph Cluster iSCSI Gateways",
186 + Fam: "status",
187 + Units: "gateways",
188 + Ctx: "ceph.cluster_iscsi_gateways_count",
189 + Type: module.Line,
190 + Priority: prioClusterIScsiGatewaysCount,
191 + Dims: module.Dims{
192 + {ID: "iscsi_daemons_num", Name: "iscsi"},
193 + },
194 + }
195 + clusterIScsiGatewaysByStatusCountChart = module.Chart{
196 + ID: "cluster_iscsi_gateways_by_status_count",
197 + Title: "Ceph Cluster iSCSI Gateways by Status",
198 + Fam: "status",
199 + Units: "gateways",
200 + Ctx: "ceph.cluster_iscsi_gateways_by_status_count",
201 + Type: module.Line,
202 + Priority: prioClusterIScsiGatewaysByStatusCount,
203 + Dims: module.Dims{
204 + {ID: "iscsi_daemons_up_num", Name: "up"},
205 + {ID: "iscsi_daemons_down_num", Name: "down"},
206 + },
207 + }
208 +)
209 +
210 +var (
211 + clusterPhysCapacityUtilizationChart = module.Chart{
212 + ID: "cluster_physical_capacity_utilization",
213 + Title: "Ceph Cluster Physical Capacity Utilization",
214 + Fam: "capacity",
215 + Units: "percent",
216 + Ctx: "ceph.cluster_physical_capacity_utilization",
217 + Type: module.Area,
218 + Priority: prioClusterPhysCapacityUtilization,
219 + Dims: module.Dims{
220 + {ID: "raw_capacity_utilization", Name: "utilization", Div: precision},
221 + },
222 + }
223 + clusterPhysCapacityUsageChart = module.Chart{
224 + ID: "cluster_physical_capacity_usage",
225 + Title: "Ceph Cluster Physical Capacity Usage",
226 + Fam: "capacity",
227 + Units: "bytes",
228 + Ctx: "ceph.cluster_physical_capacity_usage",
229 + Type: module.Stacked,
230 + Priority: prioClusterPhysCapacityUsage,
231 + Dims: module.Dims{
232 + {ID: "raw_capacity_avail_bytes", Name: "avail"},
233 + {ID: "raw_capacity_used_bytes", Name: "used"},
234 + },
235 + }
236 + clusterObjectsCountChart = module.Chart{
237 + ID: "cluster_objects_count",
238 + Title: "Ceph Cluster Objects",
239 + Fam: "capacity",
240 + Units: "objects",
241 + Ctx: "ceph.cluster_objects_count",
242 + Type: module.Line,
243 + Priority: prioClusterObjectsCount,
244 + Dims: module.Dims{
245 + {ID: "objects_num", Name: "objects"},
246 + },
247 + }
248 + clusterObjectsByStatusPercentChart = module.Chart{
249 + ID: "cluster_objects_by_status",
250 + Title: "Ceph Cluster Objects by Status",
251 + Fam: "capacity",
252 + Units: "percent",
253 + Ctx: "ceph.cluster_objects_by_status_distribution",
254 + Type: module.Stacked,
255 + Priority: prioClusterObjectsByStatusPercent,
256 + Dims: module.Dims{
257 + {ID: "objects_healthy_num", Name: "healthy", Algo: module.PercentOfAbsolute},
258 + {ID: "objects_misplaced_num", Name: "misplaced", Algo: module.PercentOfAbsolute},
259 + {ID: "objects_degraded_num", Name: "degraded", Algo: module.PercentOfAbsolute},
260 + {ID: "objects_unfound_num", Name: "unfound", Algo: module.PercentOfAbsolute},
261 + },
262 + }
263 + clusterPoolsCountChart = module.Chart{
264 + ID: "cluster_pools_count",
265 + Title: "Ceph Cluster Pools",
266 + Fam: "capacity",
267 + Units: "pools",
268 + Ctx: "ceph.cluster_pools_count",
269 + Type: module.Line,
270 + Priority: prioClusterPoolsCount,
271 + Dims: module.Dims{
272 + {ID: "pools_num", Name: "pools"},
273 + },
274 + }
275 + clusterPGsCountChart = module.Chart{
276 + ID: "cluster_pgs_count",
277 + Title: "Ceph Cluster Placement Groups",
278 + Fam: "capacity",
279 + Units: "pgs",
280 + Ctx: "ceph.cluster_pgs_count",
281 + Type: module.Line,
282 + Priority: prioClusterPGsCount,
283 + Dims: module.Dims{
284 + {ID: "pgs_num", Name: "pgs"},
285 + },
286 + }
287 + clusterPGsByStatusCountChart = module.Chart{
288 + ID: "cluster_pgs_by_status_count",
289 + Title: "Ceph Cluster Placement Groups by Status",
290 + Fam: "capacity",
291 + Units: "pgs",
292 + Ctx: "ceph.cluster_pgs_by_status_count",
293 + Type: module.Stacked,
294 + Priority: prioClusterPGsByStatusCount,
295 + Dims: module.Dims{
296 + {ID: "pg_status_category_clean", Name: "clean"},
297 + {ID: "pg_status_category_working", Name: "working"},
298 + {ID: "pg_status_category_warning", Name: "warning"},
299 + {ID: "pg_status_category_unknown", Name: "unknown"},
300 + },
301 + }
302 + clusterPgsPerOsdCountChart = module.Chart{
303 + ID: "cluster_pgs_per_osd_count",
304 + Title: "Ceph Cluster Placement Groups per OSD",
305 + Fam: "capacity",
306 + Units: "pgs",
307 + Ctx: "ceph.cluster_pgs_per_osd_count",
308 + Type: module.Line,
309 + Priority: prioClusterPGsPerOsdCount,
310 + Dims: module.Dims{
311 + {ID: "pgs_per_osd", Name: "per_osd"},
312 + },
313 + }
314 +)
315 +
316 +var (
317 + clusterClientIOChart = module.Chart{
318 + ID: "cluster_client_io",
319 + Title: "Ceph Cluster Client IO",
320 + Fam: "performance",
321 + Units: "bytes/s",
322 + Ctx: "ceph.cluster_client_io",
323 + Type: module.Area,
324 + Priority: prioClusterClientIO,
325 + Dims: module.Dims{
326 + {ID: "client_perf_read_bytes_sec", Name: "read"},
327 + {ID: "client_perf_write_bytes_sec", Name: "write", Mul: -1},
328 + },
329 + }
330 + clusterClientIOPSChart = module.Chart{
331 + ID: "cluster_client_iops",
332 + Title: "Ceph Cluster Client IOPS",
333 + Fam: "performance",
334 + Units: "ops/s",
335 + Ctx: "ceph.cluster_client_iops",
336 + Type: module.Line,
337 + Priority: prioClusterClientIOPS,
338 + Dims: module.Dims{
339 + {ID: "client_perf_read_op_per_sec", Name: "read"},
340 + {ID: "client_perf_write_op_per_sec", Name: "write", Mul: -1},
341 + },
342 + }
343 + clusterRecoveryThroughputChart = module.Chart{
344 + ID: "cluster_recovery_throughput",
345 + Title: "Ceph Cluster Recovery Throughput",
346 + Fam: "performance",
347 + Units: "bytes/s",
348 + Ctx: "ceph.cluster_recovery_throughput",
349 + Type: module.Line,
350 + Priority: prioClusterClientRecoveryThroughput,
351 + Dims: module.Dims{
352 + {ID: "client_perf_recovering_bytes_per_sec", Name: "recovery"},
353 + },
354 + }
355 + clusterScrubStatusChart = module.Chart{
356 + ID: "cluster_scrub_status",
357 + Title: "Ceph Cluster Scrubbing Status",
358 + Fam: "performance",
359 + Units: "status",
360 + Ctx: "ceph.cluster_scrub_status",
361 + Type: module.Line,
362 + Priority: prioClusterScrubStatus,
363 + Dims: module.Dims{
364 + {ID: "scrub_status_disabled", Name: "disabled"},
365 + {ID: "scrub_status_active", Name: "active"},
366 + {ID: "scrub_status_inactive", Name: "inactive"},
367 + },
368 + }
369 +)
370 +
371 +var (
372 + osdStatusChartTmpl = module.Chart{
373 + ID: "osd_%s_status",
374 + Title: "Ceph OSD Status",
375 + Fam: "osd",
376 + Units: "status",
377 + Ctx: "ceph.osd_status",
378 + Type: module.Line,
379 + Priority: prioOsdStatus,
380 + Dims: module.Dims{
381 + {ID: "osd_%s_status_up", Name: "up"},
382 + {ID: "osd_%s_status_down", Name: "down"},
383 + {ID: "osd_%s_status_in", Name: "in"},
384 + {ID: "osd_%s_status_out", Name: "out"},
385 + },
386 + }
387 + osdSpaceUsageChartTmpl = module.Chart{
388 + ID: "osd_%s_space_usage",
389 + Title: "Ceph OSD Space Usage",
390 + Fam: "osd",
391 + Units: "bytes",
392 + Ctx: "ceph.osd_space_usage",
393 + Type: module.Stacked,
394 + Priority: prioOsdSpaceUsage,
395 + Dims: module.Dims{
396 + {ID: "osd_%s_space_avail_bytes", Name: "avail"},
397 + {ID: "osd_%s_space_used_bytes", Name: "used"},
398 + },
399 + }
400 + osdIOChartTmpl = module.Chart{
401 + ID: "osd_%s_io",
402 + Title: "Ceph OSD IO",
403 + Fam: "osd",
404 + Units: "bytes/s",
405 + Ctx: "ceph.osd_io",
406 + Type: module.Area,
407 + Priority: prioOsdIO,
408 + Dims: module.Dims{
409 + {ID: "osd_%s_read_bytes", Name: "read", Algo: module.Incremental},
410 + {ID: "osd_%s_written_bytes", Name: "written", Algo: module.Incremental, Mul: -1},
411 + },
412 + }
413 + osdIOPSChartTmpl = module.Chart{
414 + ID: "osd_%s_iops",
415 + Title: "Ceph OSD IOPS",
416 + Fam: "osd",
417 + Units: "ops/s",
418 + Ctx: "ceph.osd_iops",
419 + Type: module.Line,
420 + Priority: prioOsdIOPS,
421 + Dims: module.Dims{
422 + {ID: "osd_%s_read_ops", Name: "read", Algo: module.Incremental},
423 + {ID: "osd_%s_write_ops", Name: "write", Algo: module.Incremental},
424 + },
425 + }
426 + osdLatencyChartTmpl = module.Chart{
427 + ID: "osd_%s_latency",
428 + Title: "Ceph OSD Latency",
429 + Fam: "osd",
430 + Units: "milliseconds",
431 + Ctx: "ceph.osd_latency",
432 + Type: module.Line,
433 + Priority: prioOsdLatency,
434 + Dims: module.Dims{
435 + {ID: "osd_%s_commit_latency_ms", Name: "commit"},
436 + {ID: "osd_%s_apply_latency_ms", Name: "apply"},
437 + },
438 + }
439 +)
440 +
441 +var (
442 + poolSpaceUtilizationChartTmpl = module.Chart{
443 + ID: "pool_%s_space_utilization",
444 + Title: "Ceph Pool Space Utilization",
445 + Fam: "pool",
446 + Units: "percent",
447 + Ctx: "ceph.pool_space_utilization",
448 + Type: module.Area,
449 + Priority: prioPoolSpaceUtilization,
450 + Dims: module.Dims{
451 + {ID: "pool_%s_space_utilization", Name: "utilization", Div: precision},
452 + },
453 + }
454 + poolSpaceUsageChartTmpl = module.Chart{
455 + ID: "pool_%s_space_usage",
456 + Title: "Ceph Pool Space Usage",
457 + Fam: "pool",
458 + Units: "bytes",
459 + Ctx: "ceph.pool_space_usage",
460 + Type: module.Stacked,
461 + Priority: prioPoolSpaceUsage,
462 + Dims: module.Dims{
463 + {ID: "pool_%s_space_avail_bytes", Name: "avail"},
464 + {ID: "pool_%s_space_used_bytes", Name: "used"},
465 + },
466 + }
467 + poolObjectsCountChartTmpl = module.Chart{
468 + ID: "pool_%s_objects_count",
469 + Title: "Ceph Pool Objects",
470 + Fam: "pool",
471 + Units: "objects",
472 + Ctx: "ceph.pool_objects_count",
473 + Type: module.Line,
474 + Priority: prioPoolObjectsCount,
475 + Dims: module.Dims{
476 + {ID: "pool_%s_objects", Name: "objects"},
477 + },
478 + }
479 + poolIOChartTmpl = module.Chart{
480 + ID: "pool_%s_io",
481 + Title: "Ceph Pool IO",
482 + Fam: "pool",
483 + Units: "bytes/s",
484 + Ctx: "ceph.pool_io",
485 + Type: module.Area,
486 + Priority: prioPoolIO,
487 + Dims: module.Dims{
488 + {ID: "pool_%s_read_bytes", Name: "read", Algo: module.Incremental},
489 + {ID: "pool_%s_written_bytes", Name: "written", Algo: module.Incremental, Mul: -1},
490 + },
491 + }
492 + poolIOPSChartTmpl = module.Chart{
493 + ID: "pool_%s_iops",
494 + Title: "Ceph Pool IOPS",
495 + Fam: "pool",
496 + Units: "ops/s",
497 + Ctx: "ceph.pool_iops",
498 + Type: module.Line,
499 + Priority: prioPoolIOPS,
500 + Dims: module.Dims{
501 + {ID: "pool_%s_read_ops", Name: "read", Algo: module.Incremental},
502 + {ID: "pool_%s_write_ops", Name: "write", Algo: module.Incremental, Mul: -1},
503 + },
504 + }
505 +)
506 +
507 +func (c *Ceph) addClusterCharts() {
508 + charts := clusterCharts.Copy()
509 +
510 + for _, chart := range *charts {
511 + chart.Labels = []module.Label{
512 + {Key: "fsid", Value: c.fsid},
513 + }
514 + }
515 +
516 + if err := c.Charts().Add(*charts...); err != nil {
517 + c.Warning(err)
518 + }
519 +}
520 +
521 +func (c *Ceph) addOsdCharts(osdUuid, devClass, osdName string) {
522 + charts := osdChartsTmpl.Copy()
523 +
524 + for _, chart := range *charts {
525 + chart.ID = fmt.Sprintf(chart.ID, osdUuid)
526 + chart.ID = cleanChartID(chart.ID)
527 + chart.Labels = []module.Label{
528 + {Key: "fsid", Value: c.fsid},
529 + {Key: "osd_uuid", Value: osdUuid},
530 + {Key: "osd_name", Value: osdName},
531 + {Key: "device_class", Value: devClass},
532 + }
533 + for _, dim := range chart.Dims {
534 + dim.ID = fmt.Sprintf(dim.ID, osdUuid)
535 + }
536 + }
537 +
538 + if err := c.Charts().Add(*charts...); err != nil {
539 + c.Warning(err)
540 + }
541 +}
542 +
543 +func (c *Ceph) addPoolCharts(poolName string) {
544 + charts := poolChartsTmpl.Copy()
545 +
546 + for _, chart := range *charts {
547 + chart.ID = fmt.Sprintf(chart.ID, poolName)
548 + chart.ID = cleanChartID(chart.ID)
549 + chart.Labels = []module.Label{
550 + {Key: "fsid", Value: c.fsid},
551 + {Key: "pool_name", Value: poolName},
552 + }
553 + for _, dim := range chart.Dims {
554 + dim.ID = fmt.Sprintf(dim.ID, poolName)
555 + }
556 + }
557 +
558 + if err := c.Charts().Add(*charts...); err != nil {
559 + c.Warning(err)
560 + }
561 +}
562 +
563 +func (c *Ceph) removeCharts(prefix string) {
564 + prefix = cleanChartID(prefix)
565 + for _, chart := range *c.Charts() {
566 + if strings.HasPrefix(chart.ID, prefix) {
567 + chart.MarkRemove()
568 + chart.MarkNotCreated()
569 + }
570 + }
571 +}
572 +
573 +func cleanChartID(id string) string {
574 + r := strings.NewReplacer(".", "_", " ", "_")
575 + return strings.ToLower(r.Replace(id))
576 +}
src/go/plugin/go.d/modules/ceph/collect.go new
+109
@@ -0,0 +1,109 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "encoding/json"
7 + "errors"
8 + "fmt"
9 + "net/http"
10 + "slices"
11 +
12 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
13 +)
14 +
15 +const precision = 1000
16 +
17 +func (c *Ceph) collect() (map[string]int64, error) {
18 + mx := make(map[string]int64)
19 +
20 + if err := c.auth(); err != nil {
21 + return nil, err
22 + }
23 +
24 + if c.fsid == "" {
25 + fsid, err := c.getFsid()
26 + if err != nil {
27 + return nil, fmt.Errorf("failed to get fsid: %v", err)
28 + }
29 + c.fsid = fsid
30 + c.addClusterChartsOnce.Do(c.addClusterCharts)
31 + }
32 +
33 + if err := c.collectHealth(mx); err != nil {
34 + return nil, fmt.Errorf("failed to collect health: %v", err)
35 + }
36 + if err := c.collectOsds(mx); err != nil {
37 + return nil, fmt.Errorf("failed to collect osds: %v", err)
38 + }
39 + if err := c.collectPools(mx); err != nil {
40 + return nil, fmt.Errorf("failed to collect pools: %v", err)
41 + }
42 +
43 + return mx, nil
44 +}
45 +
46 +func (c *Ceph) auth() error {
47 + if c.token != "" {
48 + ok, err := c.authCheck()
49 + if err != nil {
50 + return err
51 + }
52 + if ok {
53 + return nil
54 + }
55 + c.token = ""
56 + }
57 +
58 + tok, err := c.authLogin()
59 + if err != nil {
60 + return err
61 + }
62 + c.token = tok
63 +
64 + return nil
65 +}
66 +
67 +func (c *Ceph) getFsid() (string, error) {
68 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiMonitor)
69 + if err != nil {
70 + return "", err
71 + }
72 +
73 + req.Header.Set("Accept", hdrAcceptVersion)
74 + req.Header.Set("Content-Type", hdrContentTypeJson)
75 + req.Header.Set("Authorization", "Bearer "+c.token)
76 +
77 + var resp struct {
78 + MonStatus struct {
79 + MonMap struct {
80 + FSID string `json:"fsid"`
81 + } `json:"monmap"`
82 + } `json:"mon_status"`
83 + }
84 +
85 + if err := c.webClient().RequestJSON(req, &resp); err != nil {
86 + return "", err
87 + }
88 +
89 + if resp.MonStatus.MonMap.FSID == "" {
90 + return "", errors.New("no fsid")
91 + }
92 +
93 + return resp.MonStatus.MonMap.FSID, nil
94 +}
95 +
96 +func (c *Ceph) webClient(statusCodes ...int) *web.Client {
97 + return web.DoHTTP(c.httpClient).OnNokCode(func(resp *http.Response) (bool, error) {
98 + if slices.Contains(statusCodes, resp.StatusCode) {
99 + return true, nil
100 + }
101 + var msg struct {
102 + Detail string `json:"detail"`
103 + }
104 + if err := json.NewDecoder(resp.Body).Decode(&msg); err == nil && msg.Detail != "" {
105 + return false, errors.New(msg.Detail)
106 + }
107 + return false, nil
108 + })
109 +}
src/go/plugin/go.d/modules/ceph/collect_health.go new
+155
@@ -0,0 +1,155 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "strings"
7 +
8 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
9 +)
10 +
11 +func (c *Ceph) collectHealth(mx map[string]int64) error {
12 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiHealthMinimal)
13 + if err != nil {
14 + return err
15 + }
16 +
17 + req.Header.Set("Accept", hdrAcceptVersion)
18 + req.Header.Set("Content-Type", hdrContentTypeJson)
19 + req.Header.Set("Authorization", "Bearer "+c.token)
20 +
21 + var resp apiHealthMinimalResponse
22 +
23 + if err := c.webClient().RequestJSON(req, &resp); err != nil {
24 + return err
25 + }
26 +
27 + for _, v := range []string{"health_err", "health_warn", "health_ok"} {
28 + mx[v] = 0
29 + }
30 + mx[strings.ToLower(resp.Health.Status)] = 1
31 +
32 + mx["mgr_active_num"] = 0
33 + if resp.MgrMap.ActiveName != "" {
34 + mx["mgr_active_num"] = 1
35 + }
36 + mx["mgr_standby_num"] = int64(len(resp.MgrMap.Standbys))
37 + mx["hosts_num"] = resp.Hosts
38 + mx["rgw_num"] = resp.Rgw
39 + mx["monitors_num"] = int64(len(resp.MonStatus.MonMap.Mons))
40 + mx["osds_num"] = int64(len(resp.OsdMap.Osds))
41 +
42 + for _, v := range []string{"up", "down", "in", "out"} {
43 + mx["osds_"+v+"_num"] = 0
44 + }
45 + for _, v := range resp.OsdMap.Osds {
46 + s := map[int64]string{0: "out", 1: "in"}
47 + mx["osds_"+s[v.In]+"_num"]++
48 +
49 + s = map[int64]string{0: "down", 1: "up"}
50 + mx["osds_"+s[v.Up]+"_num"]++
51 + }
52 +
53 + mx["pools_num"] = int64(len(resp.Pools))
54 + mx["iscsi_daemons_num"] = resp.IscsiDaemons.Up + resp.IscsiDaemons.Down
55 + mx["iscsi_daemons_up_num"] = resp.IscsiDaemons.Up
56 + mx["iscsi_daemons_down_num"] = resp.IscsiDaemons.Down
57 +
58 + df := resp.Df.Stats
59 + mx["raw_capacity_used_bytes"] = df.TotalBytes - df.TotalAvailBytes
60 + mx["raw_capacity_avail_bytes"] = df.TotalAvailBytes
61 + mx["raw_capacity_utilization"] = 0
62 + if df.TotalAvailBytes > 0 {
63 + mx["raw_capacity_utilization"] = int64(float64(df.TotalBytes-df.TotalAvailBytes) / float64(df.TotalBytes) * 100 * precision)
64 + }
65 +
66 + objs := resp.PgInfo.ObjectStats
67 + mx["objects_num"] = objs.NumObjects
68 + mx["objects_healthy_num"] = objs.NumObjects - (objs.NumObjectsMisplaced + objs.NumObjectsDegraded + objs.NumObjectsUnfound)
69 + mx["objects_misplaced_num"] = objs.NumObjectsMisplaced
70 + mx["objects_degraded_num"] = objs.NumObjectsDegraded
71 + mx["objects_unfound_num"] = objs.NumObjectsUnfound
72 + mx["pgs_per_osd"] = int64(resp.PgInfo.PgsPerOsd)
73 +
74 + mx["pgs_num"] = 0
75 + for _, v := range []string{"clean", "working", "warning", "unknown"} {
76 + mx["pg_status_category_"+v] = 0
77 + }
78 + for k, v := range resp.PgInfo.Statuses {
79 + mx["pg_status_category_"+pgStatusCategory(k)] += v
80 + mx["pgs_num"] += v
81 + }
82 +
83 + perf := resp.ClientPerf
84 + mx["client_perf_read_bytes_sec"] = int64(perf.ReadBytesSec)
85 + mx["client_perf_read_op_per_sec"] = int64(perf.ReadOpPerSec)
86 + mx["client_perf_write_bytes_sec"] = int64(perf.WriteBytesSec)
87 + mx["client_perf_write_op_per_sec"] = int64(perf.WriteOpPerSec)
88 + mx["client_perf_recovering_bytes_per_sec"] = int64(perf.RecoveringBytesPerSec)
89 +
90 + for _, v := range []string{"disabled", "active", "inactive"} {
91 + mx["scrub_status_"+v] = 0
92 + }
93 + mx["scrub_status_"+strings.ToLower(resp.ScrubStatus)] = 1
94 +
95 + return nil
96 +}
97 +
98 +func pgStatusCategory(status string) string {
99 + // 'status' is formated as 'status1+status2+...+statusN'
100 +
101 + states := strings.Split(status, "+")
102 +
103 + var clean, working, warning, unknown int
104 +
105 + for _, s := range states {
106 + switch s {
107 + case "active", "clean":
108 + clean++
109 + case "activating",
110 + "backfill_wait",
111 + "backfilling",
112 + "creating",
113 + "deep",
114 + "degraded",
115 + "forced_backfill",
116 + "forced_recovery",
117 + "peering",
118 + "peered",
119 + "recovering",
120 + "recovery_wait",
121 + "repair",
122 + "scrubbing",
123 + "snaptrim",
124 + "snaptrim_wait":
125 + working++
126 + case "backfill_toofull",
127 + "backfill_unfound",
128 + "down",
129 + "incomplete",
130 + "inconsistent",
131 + "recovery_toofull",
132 + "recovery_unfound",
133 + "remapped",
134 + "snaptrim_error",
135 + "stale",
136 + "undersized":
137 + warning++
138 + default:
139 + unknown++
140 + }
141 + }
142 +
143 + switch {
144 + case warning > 0:
145 + return "warning"
146 + case unknown > 0:
147 + return "unknown"
148 + case working > 0:
149 + return "working"
150 + case clean > 0:
151 + return "clean"
152 + default:
153 + return "unknown"
154 + }
155 +}
src/go/plugin/go.d/modules/ceph/collect_osd.go new
+66
@@ -0,0 +1,66 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "fmt"
7 +
8 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
9 +)
10 +
11 +func (c *Ceph) collectOsds(mx map[string]int64) error {
12 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiOsd)
13 + if err != nil {
14 + return err
15 + }
16 +
17 + req.Header.Set("Accept", hdrAcceptVersion)
18 + req.Header.Set("Content-Type", hdrContentTypeJson)
19 + req.Header.Set("Authorization", "Bearer "+c.token)
20 +
21 + var osds []apiOsdResponse
22 +
23 + if err := c.webClient().RequestJSON(req, &osds); err != nil {
24 + return err
25 + }
26 +
27 + seen := make(map[string]bool)
28 +
29 + for _, osd := range osds {
30 + px := fmt.Sprintf("osd_%s_", osd.UUID)
31 +
32 + seen[osd.UUID] = true
33 + if !c.seenOsds[osd.UUID] {
34 + c.seenOsds[osd.UUID] = true
35 + c.addOsdCharts(osd.UUID, osd.Tree.DeviceClass, osd.Tree.Name)
36 + }
37 +
38 + mx[px+"status_up"], mx[px+"status_down"] = 1, 0
39 + if osd.Up == 0 {
40 + mx[px+"status_up"], mx[px+"status_down"] = 0, 1
41 + }
42 + mx[px+"status_in"], mx[px+"status_out"] = 1, 0
43 + if osd.In == 0 {
44 + mx[px+"status_in"], mx[px+"status_out"] = 0, 1
45 + }
46 +
47 + mx[px+"size_bytes"] = osd.OsdStats.Statfs.Total
48 + mx[px+"space_used_bytes"] = osd.OsdStats.Statfs.Total - osd.OsdStats.Statfs.Available
49 + mx[px+"space_avail_bytes"] = osd.OsdStats.Statfs.Available
50 + mx[px+"read_ops"] = int64(osd.Stats.OpR)
51 + mx[px+"read_bytes"] = int64(osd.Stats.OpOutBytes)
52 + mx[px+"write_ops"] = int64(osd.Stats.OpW)
53 + mx[px+"written_bytes"] = int64(osd.Stats.OpInBytes)
54 + mx[px+"commit_latency_ms"] = int64(osd.OsdStats.PerfStat.CommitLatencyMs)
55 + mx[px+"apply_latency_ms"] = int64(osd.OsdStats.PerfStat.ApplyLatencyMs)
56 + }
57 +
58 + for uuid := range c.seenOsds {
59 + if !seen[uuid] {
60 + delete(c.seenOsds, uuid)
61 + c.removeCharts(fmt.Sprintf("osd_%s_", uuid))
62 + }
63 + }
64 +
65 + return nil
66 +}
src/go/plugin/go.d/modules/ceph/collect_pools.go new
+58
@@ -0,0 +1,58 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "fmt"
7 +
8 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
9 +)
10 +
11 +func (c *Ceph) collectPools(mx map[string]int64) error {
12 + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathApiPool)
13 + if err != nil {
14 + return err
15 + }
16 +
17 + req.URL.RawQuery = urlQueryApiPool
18 + req.Header.Set("Accept", hdrAcceptVersion)
19 + req.Header.Set("Content-Type", hdrContentTypeJson)
20 + req.Header.Set("Authorization", "Bearer "+c.token)
21 +
22 + var pools []apiPoolResponse
23 +
24 + if err := c.webClient().RequestJSON(req, &pools); err != nil {
25 + return err
26 + }
27 +
28 + seen := make(map[string]bool)
29 +
30 + for _, pool := range pools {
31 + px := fmt.Sprintf("pool_%s_", pool.PoolName)
32 +
33 + seen[pool.PoolName] = true
34 + if !c.seenPools[pool.PoolName] {
35 + c.seenPools[pool.PoolName] = true
36 + c.addPoolCharts(pool.PoolName)
37 + }
38 +
39 + mx[px+"objects"] = int64(pool.Stats.Objects.Latest)
40 + mx[px+"size"] = int64(pool.Stats.AvailRaw.Latest)
41 + mx[px+"space_used_bytes"] = int64(pool.Stats.BytesUsed.Latest)
42 + mx[px+"space_avail_bytes"] = int64(pool.Stats.AvailRaw.Latest - pool.Stats.BytesUsed.Latest)
43 + mx[px+"space_utilization"] = int64(pool.Stats.PercentUsed.Latest * precision)
44 + mx[px+"read_ops"] = int64(pool.Stats.Reads.Latest)
45 + mx[px+"read_bytes"] = int64(pool.Stats.ReadBytes.Latest)
46 + mx[px+"write_ops"] = int64(pool.Stats.Writes.Latest)
47 + mx[px+"written_bytes"] = int64(pool.Stats.WrittenBytes.Latest)
48 + }
49 +
50 + for name := range c.seenPools {
51 + if !seen[name] {
52 + delete(c.seenPools, name)
53 + c.removeCharts(fmt.Sprintf("pool_%s_", name))
54 + }
55 + }
56 +
57 + return nil
58 +}
src/go/plugin/go.d/modules/ceph/config_schema.json new
+186
@@ -0,0 +1,186 @@
1 +{
2 + "jsonSchema": {
3 + "$schema": "http://json-schema.org/draft-07/schema#",
4 + "title": "Ceph collector configuration.",
5 + "type": "object",
6 + "properties": {
7 + "update_every": {
8 + "title": "Update every",
9 + "description": "Data collection interval, measured in seconds.",
10 + "type": "integer",
11 + "minimum": 1,
12 + "default": 10
13 + },
14 + "url": {
15 + "title": "URL",
16 + "description": "The URL of the [Ceph Manager API](https://docs.ceph.com/en/reef/mgr/ceph_api/).",
17 + "type": "string",
18 + "default": "https://127.0.0.1:8443",
19 + "format": "uri"
20 + },
21 + "timeout": {
22 + "title": "Timeout",
23 + "description": "The timeout in seconds for the HTTP request.",
24 + "type": "number",
25 + "minimum": 0.5,
26 + "default": 2
27 + },
28 + "not_follow_redirects": {
29 + "title": "Not follow redirects",
30 + "description": "If set, the client will not follow HTTP redirects automatically.",
31 + "type": "boolean"
32 + },
33 + "username": {
34 + "title": "Username",
35 + "description": "The username for basic authentication.",
36 + "type": "string",
37 + "sensitive": true
38 + },
39 + "password": {
40 + "title": "Password",
41 + "description": "The password for basic authentication.",
42 + "type": "string",
43 + "sensitive": true
44 + },
45 + "proxy_url": {
46 + "title": "Proxy URL",
47 + "description": "The URL of the proxy server.",
48 + "type": "string"
49 + },
50 + "proxy_username": {
51 + "title": "Proxy username",
52 + "description": "The username for proxy authentication.",
53 + "type": "string",
54 + "sensitive": true
55 + },
56 + "proxy_password": {
57 + "title": "Proxy password",
58 + "description": "The password for proxy authentication.",
59 + "type": "string",
60 + "sensitive": true
61 + },
62 + "headers": {
63 + "title": "Headers",
64 + "description": "Additional HTTP headers to include in the request.",
65 + "type": [
66 + "object",
67 + "null"
68 + ],
69 + "additionalProperties": {
70 + "type": "string"
71 + }
72 + },
73 + "tls_skip_verify": {
74 + "title": "Skip TLS verification",
75 + "description": "If set, TLS certificate verification will be skipped.",
76 + "type": "boolean",
77 + "default": true
78 + },
79 + "tls_ca": {
80 + "title": "TLS CA",
81 + "description": "The path to the CA certificate file for TLS verification.",
82 + "type": "string",
83 + "pattern": "^$|^/"
84 + },
85 + "tls_cert": {
86 + "title": "TLS certificate",
87 + "description": "The path to the client certificate file for TLS authentication.",
88 + "type": "string",
89 + "pattern": "^$|^/"
90 + },
91 + "tls_key": {
92 + "title": "TLS key",
93 + "description": "The path to the client key file for TLS authentication.",
94 + "type": "string",
95 + "pattern": "^$|^/"
96 + },
97 + "body": {
98 + "title": "Body",
99 + "type": "string"
100 + },
101 + "method": {
102 + "title": "Method",
103 + "type": "string"
104 + }
105 + },
106 + "required": [
107 + "url",
108 + "username",
109 + "password"
110 + ],
111 + "additionalProperties": false,
112 + "patternProperties": {
113 + "^name$": {}
114 + }
115 + },
116 + "uiSchema": {
117 + "uiOptions": {
118 + "fullPage": true
119 + },
120 + "body": {
121 + "ui:widget": "hidden"
122 + },
123 + "method": {
124 + "ui:widget": "hidden"
125 + },
126 + "timeout": {
127 + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
128 + },
129 + "username": {
130 + "ui:widget": "password"
131 + },
132 + "proxy_username": {
133 + "ui:widget": "password"
134 + },
135 + "password": {
136 + "ui:widget": "password"
137 + },
138 + "proxy_password": {
139 + "ui:widget": "password"
140 + },
141 + "ui:flavour": "tabs",
142 + "ui:options": {
143 + "tabs": [
144 + {
145 + "title": "Base",
146 + "fields": [
147 + "update_every",
148 + "url",
149 + "timeout",
150 + "not_follow_redirects"
151 + ]
152 + },
153 + {
154 + "title": "Auth",
155 + "fields": [
156 + "username",
157 + "password"
158 + ]
159 + },
160 + {
161 + "title": "TLS",
162 + "fields": [
163 + "tls_skip_verify",
164 + "tls_ca",
165 + "tls_cert",
166 + "tls_key"
167 + ]
168 + },
169 + {
170 + "title": "Proxy",
171 + "fields": [
172 + "proxy_url",
173 + "proxy_username",
174 + "proxy_password"
175 + ]
176 + },
177 + {
178 + "title": "Headers",
179 + "fields": [
180 + "headers"
181 + ]
182 + }
183 + ]
184 + }
185 + }
186 +}
src/go/plugin/go.d/modules/ceph/init.go new
+17
@@ -0,0 +1,17 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package ceph
4 +
5 +import (
6 + "fmt"
7 +)
8 +
9 +func (c *Ceph) validateConfig() error {
10 + if c.URL == "" {
11 + return fmt.Errorf("URL is required but not set")
12 + }
13 + if c.Username == "" || c.Password == "" {
14 + return fmt.Errorf("username and password are required but not set")
15 + }
16 + return nil
17 +}
src/go/plugin/go.d/modules/ceph/metadata.yaml new
+391
@@ -0,0 +1,391 @@
1 +plugin_name: go.d.plugin
2 +modules:
3 + - meta:
4 + plugin_name: go.d.plugin
5 + module_name: ceph
6 + monitored_instance:
7 + name: Ceph
8 + link: "https://ceph.io/"
9 + categories:
10 + - data-collection.storage-mount-points-and-filesystems
11 + icon_filename: "ceph.svg"
12 + related_resources:
13 + integrations:
14 + list: []
15 + info_provided_to_referring_integrations:
16 + description: ""
17 + keywords:
18 + - ceph
19 + - storage
20 + most_popular: false
21 + overview:
22 + data_collection:
23 + metrics_description: |
24 + This collector monitors the overall health status and performance of your Ceph clusters.
25 + It gathers key metrics for the entire cluster, individual Pools, and OSDs
26 + method_description: |
27 + It collects metrics by periodically issuing HTTP GET requests to the Ceph Manager [RESP API](https://docs.ceph.com/en/reef/mgr/ceph_api/#):
28 +
29 + - [/api/monitor](https://docs.ceph.com/en/reef/mgr/ceph_api/#get--api-monitor) (only once to get the Ceph cluster id (fsid))
30 + - [/api/health/minimal](https://docs.ceph.com/en/reef/mgr/ceph_api/#get--api-health-minimal)
31 + - [/api/osd](https://docs.ceph.com/en/reef/mgr/ceph_api/#get--api-osd)
32 + - [/api/pool?stats=true](https://docs.ceph.com/en/reef/mgr/ceph_api/#get--api-pool)
33 + supported_platforms:
34 + include: [Linux]
35 + exclude: []
36 + multi_instance: true
37 + additional_permissions:
38 + description: ""
39 + default_behavior:
40 + auto_detection:
41 + description: |
42 + The collector can automatically detect Ceph Manager instances running on:
43 +
44 + - localhost that are listening on port 8443
45 + - within Docker containers
46 +
47 + > **Note that the Ceph RESP API requires a username and password**.
48 + > While Netdata can automatically detect Ceph Manager instances and create data collection jobs, these jobs will fail unless you provide the necessary credentials.
49 + limits:
50 + description: ""
51 + performance_impact:
52 + description: ""
53 + setup:
54 + prerequisites:
55 + list: []
56 + configuration:
57 + file:
58 + name: go.d/ceph.conf
59 + options:
60 + description: |
61 + The following options can be defined globally: update_every.
62 + folding:
63 + title: Config options
64 + enabled: true
65 + list:
66 + - name: update_every
67 + description: Data collection frequency.
68 + default_value: 1
69 + required: false
70 + - name: autodetection_retry
71 + description: Recheck interval in seconds. Zero means no recheck will be scheduled.
72 + default_value: 0
73 + required: false
74 + - name: url
75 + description: The URL of the [Ceph Manager API](https://docs.ceph.com/en/reef/mgr/ceph_api/).
76 + default_value: https://127.0.0.1:8443
77 + required: true
78 + - name: timeout
79 + description: HTTP request timeout.
80 + default_value: 2
81 + required: false
82 + - name: username
83 + description: Username for basic HTTP authentication.
84 + default_value: ""
85 + required: true
86 + - name: password
87 + description: Password for basic HTTP authentication.
88 + default_value: ""
89 + required: true
90 + - name: proxy_url
91 + description: Proxy URL.
92 + default_value: ""
93 + required: false
94 + - name: proxy_username
95 + description: Username for proxy basic HTTP authentication.
96 + default_value: ""
97 + required: false
98 + - name: proxy_password
99 + description: Password for proxy basic HTTP authentication.
100 + default_value: ""
101 + required: false
102 + - name: method
103 + description: HTTP request method.
104 + default_value: "GET"
105 + required: false
106 + - name: body
107 + description: HTTP request body.
108 + default_value: ""
109 + required: false
110 + - name: headers
111 + description: HTTP request headers.
112 + default_value: ""
113 + required: false
114 + - name: not_follow_redirects
115 + description: Redirect handling policy. Controls whether the client follows redirects.
116 + default_value: no
117 + required: false
118 + - name: tls_skip_verify
119 + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check.
120 + default_value: yes
121 + required: false
122 + - name: tls_ca
123 + description: Certification authority that the client uses when verifying the server's certificates.
124 + default_value: ""
125 + required: false
126 + - name: tls_cert
127 + description: Client TLS certificate.
128 + default_value: ""
129 + required: false
130 + - name: tls_key
131 + description: Client TLS key.
132 + default_value: ""
133 + required: false
134 + examples:
135 + folding:
136 + title: ""
137 + enabled: false
138 + list:
139 + - name: Basic
140 + description: A basic example configuration.
141 + folding:
142 + enabled: false
143 + config: |
144 + jobs:
145 + - name: local
146 + url: https://127.0.0.1:8443
147 + username: user
148 + password: pass
149 + - name: Multi-instance
150 + description: |
151 + > **Note**: When you define multiple jobs, their names must be unique.
152 +
153 + Collecting metrics from local and remote instances.
154 + config: |
155 + jobs:
156 + - name: local
157 + url: https://127.0.0.1:8443
158 + username: user
159 + password: pass
160 +
161 + - name: remote
162 + url: https://192.0.2.1:8443
163 + username: user
164 + password: pass
165 + troubleshooting:
166 + problems:
167 + list: []
168 + alerts:
169 + - name: ceph_cluster_space_usage
170 + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/ceph.conf
171 + metric: ceph.general_usage
172 + info: cluster disk space utilization
173 + metrics:
174 + folding:
175 + title: Metrics
176 + enabled: false
177 + description: ""
178 + availability: []
179 + scopes:
180 + - name: cluster
181 + description: "These metrics refer to the entire Ceph cluster."
182 + labels:
183 + - name: fsid
184 + description: A unique identifier of the cluster.
185 + metrics:
186 + - name: ceph.cluster_status
187 + description: Ceph Cluster Status
188 + unit: status
189 + chart_type: line
190 + dimensions:
191 + - name: ok
192 + - name: err
193 + - name: warn
194 + - name: ceph.cluster_hosts_count
195 + description: Ceph Cluster Hosts
196 + unit: hosts
197 + chart_type: line
198 + dimensions:
199 + - name: hosts
200 + - name: ceph.cluster_monitors_count
201 + description: Ceph Cluster Monitors
202 + unit: monitors
203 + chart_type: line
204 + dimensions:
205 + - name: monitors
206 + - name: ceph.cluster_osds_count
207 + description: Ceph Cluster OSDs
208 + unit: osds
209 + chart_type: line
210 + dimensions:
211 + - name: osds
212 + - name: ceph.cluster_osds_by_status_count
213 + description: Ceph Cluster OSDs by Status
214 + unit: status
215 + chart_type: line
216 + dimensions:
217 + - name: up
218 + - name: down
219 + - name: in
220 + - name: out
221 + - name: ceph.cluster_managers_count
222 + description: Ceph Cluster Managers
223 + unit: managers
224 + chart_type: line
225 + dimensions:
226 + - name: active
227 + - name: standby
228 + - name: ceph.cluster_object_gateways_count
229 + description: Ceph Cluster Object Gateways (RGW)
230 + unit: gateways
231 + chart_type: line
232 + dimensions:
233 + - name: object
234 + - name: ceph.cluster_iscsi_gateways_count
235 + description: Ceph Cluster iSCSI Gateways
236 + unit: gateways
237 + chart_type: line
238 + dimensions:
239 + - name: iscsi
240 + - name: ceph.cluster_iscsi_gateways_by_status_count
241 + description: Ceph Cluster iSCSI Gateways by Status
242 + unit: gateways
243 + chart_type: line
244 + dimensions:
245 + - name: up
246 + - name: down
247 + - name: ceph.cluster_physical_capacity_utilization
248 + description: Ceph Cluster Physical Capacity Utilization
249 + unit: percent
250 + chart_type: area
251 + dimensions:
252 + - name: utilization
253 + - name: ceph.cluster_physical_capacity_usage
254 + description: Ceph Cluster Physical Capacity Usage
255 + unit: bytes
256 + chart_type: stacked
257 + dimensions:
258 + - name: avail
259 + - name: used
260 + - name: ceph.cluster_objects_count
261 + description: Ceph Cluster Objects
262 + unit: objects
263 + chart_type: line
264 + dimensions:
265 + - name: objects
266 + - name: ceph.cluster_objects_by_status_distribution
267 + description: Ceph Cluster Objects by Status
268 + unit: percent
269 + chart_type: stacked
270 + dimensions:
271 + - name: healthy
272 + - name: misplaced
273 + - name: degraded
274 + - name: unfound
275 + - name: ceph.cluster_pools_count
276 + description: Ceph Cluster Pools
277 + unit: pools
278 + chart_type: line
279 + dimensions:
280 + - name: pools
281 + - name: ceph.cluster_pgs_count
282 + description: Ceph Cluster Placement Groups
283 + unit: pgs
284 + chart_type: line
285 + dimensions:
286 + - name: pgs
287 + - name: ceph.cluster_pgs_by_status_count
288 + description: Ceph Cluster Placement Groups by Status
289 + unit: pgs
290 + chart_type: stacked
291 + dimensions:
292 + - name: clean
293 + - name: working
294 + - name: warning
295 + - name: unknown
296 + - name: ceph.cluster_pgs_per_osd_count
297 + description: Ceph Cluster Placement Groups per OSD
298 + unit: pgs
299 + chart_type: line
300 + dimensions:
301 + - name: per_osd
302 + - name: osd
303 + description: These metrics refer to the Object Storage Daemon (OSD).
304 + labels:
305 + - name: fsid
306 + description: A unique identifier of the cluster.
307 + - name: osd_uuid
308 + description: OSD UUID.
309 + - name: osd_name
310 + description: OSD name.
311 + - name: device_class
312 + description: OSD device class.
313 + metrics:
314 + - name: ceph.osd_status
315 + description: Ceph OSD Status
316 + unit: status
317 + chart_type: line
318 + dimensions:
319 + - name: up
320 + - name: down
321 + - name: in
322 + - name: out
323 + - name: ceph.osd_space_usage
324 + description: Ceph OSD Space Usage
325 + unit: bytes
326 + chart_type: stacked
327 + dimensions:
328 + - name: avail
329 + - name: used
330 + - name: ceph.osd_io
331 + description: Ceph OSD IO
332 + unit: bytes/s
333 + chart_type: area
334 + dimensions:
335 + - name: read
336 + - name: written
337 + - name: ceph.osd_iops
338 + description: Ceph OSD IOPS
339 + unit: ops/s
340 + chart_type: area
341 + dimensions:
342 + - name: read
343 + - name: write
344 + - name: ceph.osd_latency
345 + description: Ceph OSD Latency
346 + unit: milliseconds
347 + chart_type: line
348 + dimensions:
349 + - name: commit
350 + - name: apply
351 + - name: pool
352 + description: These metrics refer to the Pool.
353 + labels:
354 + - name: fsid
355 + description: A unique identifier of the cluster.
356 + - name: pool_name
357 + description: Pool name.
358 + metrics:
359 + - name: ceph.pool_space_utilization
360 + description: Ceph Pool Space Utilization
361 + unit: percent
362 + chart_type: area
363 + dimensions:
364 + - name: utilization
365 + - name: ceph.pool_space_usage
366 + description: Ceph Pool Space Usage
367 + unit: bytes
368 + chart_type: stacked
369 + dimensions:
370 + - name: avail
371 + - name: used
372 + - name: ceph.pool_objects_count
373 + description: Ceph Pool Objects
374 + unit: objects
375 + chart_type: line
376 + dimensions:
377 + - name: object
378 + - name: ceph.pool_io
379 + description: Ceph Pool IO
380 + unit: bytes/s
381 + chart_type: area
382 + dimensions:
383 + - name: read
384 + - name: written
385 + - name: ceph.pool_iops
386 + description: Ceph Pool IOPS
387 + unit: ops/s
388 + chart_type: area
389 + dimensions:
390 + - name: read
391 + - name: write
src/go/plugin/go.d/modules/ceph/testdata/config.json new
+20
@@ -0,0 +1,20 @@
1 +{
2 + "update_every": 123,
3 + "url": "ok",
4 + "body": "ok",
5 + "method": "ok",
6 + "headers": {
7 + "ok": "ok"
8 + },
9 + "username": "ok",
10 + "password": "ok",
11 + "proxy_url": "ok",
12 + "proxy_username": "ok",
13 + "proxy_password": "ok",
14 + "timeout": 123.123,
15 + "not_follow_redirects": true,
16 + "tls_ca": "ok",
17 + "tls_cert": "ok",
18 + "tls_key": "ok",
19 + "tls_skip_verify": true
20 +}
src/go/plugin/go.d/modules/ceph/testdata/config.yaml new
+17
@@ -0,0 +1,17 @@
1 +update_every: 123
2 +url: "ok"
3 +body: "ok"
4 +method: "ok"
5 +headers:
6 + ok: "ok"
7 +username: "ok"
8 +password: "ok"
9 +proxy_url: "ok"
10 +proxy_username: "ok"
11 +proxy_password: "ok"
12 +timeout: 123.123
13 +not_follow_redirects: yes
14 +tls_ca: "ok"
15 +tls_cert: "ok"
16 +tls_key: "ok"
17 +tls_skip_verify: yes
src/go/plugin/go.d/modules/ceph/testdata/v16.2.15/api_health_minimal.json new
+105
@@ -0,0 +1,105 @@
1 +{
2 + "health": {
3 + "status": "HEALTH_WARN",
4 + "checks": [
5 + {
6 + "severity": "HEALTH_WARN",
7 + "summary": {
8 + "message": "Reduced data availability: 1 pg inactive, 1 pg incomplete",
9 + "count": 2
10 + },
11 + "detail": [
12 + {
13 + "message": "pg 1.0 is creating+incomplete, acting [1,2147483647,2147483647,2147483647] (reducing pool mySuperPool min_size from 3 may help; search ceph.com/docs for 'incomplete')"
14 + }
15 + ],
16 + "muted": false,
17 + "type": "PG_AVAILABILITY"
18 + }
19 + ],
20 + "mutes": []
21 + },
22 + "mon_status": {
23 + "monmap": {
24 + "mons": [
25 + {}
26 + ]
27 + },
28 + "quorum": [
29 + 0
30 + ]
31 + },
32 + "fs_map": {
33 + "filesystems": [],
34 + "standbys": []
35 + },
36 + "osd_map": {
37 + "osds": [
38 + {
39 + "in": 1,
40 + "up": 1,
41 + "state": [
42 + "exists",
43 + "up"
44 + ]
45 + },
46 + {
47 + "in": 1,
48 + "up": 1,
49 + "state": [
50 + "exists",
51 + "up"
52 + ]
53 + }
54 + ]
55 + },
56 + "scrub_status": "Inactive",
57 + "pg_info": {
58 + "object_stats": {
59 + "num_objects": 6,
60 + "num_object_copies": 6,
61 + "num_objects_degraded": 1,
62 + "num_objects_misplaced": 1,
63 + "num_objects_unfound": 1
64 + },
65 + "statuses": {
66 + "active+clean": 1,
67 + "creating+incomplete": 1
68 + },
69 + "pgs_per_osd": 2
70 + },
71 + "mgr_map": {
72 + "active_name": "pve-deb-work.snrdap",
73 + "standbys": [
74 + {
75 + "gid": 24118,
76 + "name": "pve-deb-work.rjothn",
77 + "mgr_features": 4540138314316775400
78 + }
79 + ]
80 + },
81 + "pools": [
82 + {},
83 + {}
84 + ],
85 + "df": {
86 + "stats": {
87 + "total_avail_bytes": 175476178944,
88 + "total_bytes": 176085270528,
89 + "total_used_raw_bytes": 609091584
90 + }
91 + },
92 + "client_perf": {
93 + "read_bytes_sec": 1,
94 + "read_op_per_sec": 1,
95 + "recovering_bytes_per_sec": 1,
96 + "write_bytes_sec": 1,
97 + "write_op_per_sec": 1
98 + },
99 + "hosts": 1,
100 + "rgw": 1,
101 + "iscsi_daemons": {
102 + "up": 1,
103 + "down": 1
104 + }
105 +}
src/go/plugin/go.d/modules/ceph/testdata/v16.2.15/api_monitor.json new
+315
@@ -0,0 +1,315 @@
1 +{
2 + "mon_status": {
3 + "name": "pve-deb-work",
4 + "rank": 0,
5 + "state": "leader",
6 + "election_epoch": 7,
7 + "quorum": [
8 + 0
9 + ],
10 + "quorum_age": 315075,
11 + "features": {
12 + "required_con": "2449958747317026820",
13 + "required_mon": [
14 + "kraken",
15 + "luminous",
16 + "mimic",
17 + "osdmap-prune",
18 + "nautilus",
19 + "octopus",
20 + "pacific",
21 + "elector-pinging"
22 + ],
23 + "quorum_con": "4540138314316775423",
24 + "quorum_mon": [
25 + "kraken",
26 + "luminous",
27 + "mimic",
28 + "osdmap-prune",
29 + "nautilus",
30 + "octopus",
31 + "pacific",
32 + "elector-pinging"
33 + ]
34 + },
35 + "outside_quorum": [],
36 + "extra_probe_peers": [],
37 + "sync_provider": [],
38 + "monmap": {
39 + "epoch": 1,
40 + "fsid": "28c31cb4-79ce-11ef-9a4d-e6007f1f06b0",
41 + "modified": "2024-09-23T17:06:26.264498Z",
42 + "created": "2024-09-23T17:06:26.264498Z",
43 + "min_mon_release": 16,
44 + "min_mon_release_name": "pacific",
45 + "election_strategy": 1,
46 + "disallowed_leaders: ": "",
47 + "stretch_mode": false,
48 + "tiebreaker_mon": "",
49 + "removed_ranks: ": "",
50 + "features": {
51 + "persistent": [
52 + "kraken",
53 + "luminous",
54 + "mimic",
55 + "osdmap-prune",
56 + "nautilus",
57 + "octopus",
58 + "pacific",
59 + "elector-pinging"
60 + ],
61 + "optional": []
62 + },
63 + "mons": [
64 + {
65 + "rank": 0,
66 + "name": "pve-deb-work",
67 + "public_addrs": {
68 + "addrvec": [
69 + {
70 + "type": "v2",
71 + "addr": "127.0.0.1:3300",
72 + "nonce": 0
73 + },
74 + {
75 + "type": "v1",
76 + "addr": "127.0.0.1:6789",
77 + "nonce": 0
78 + }
79 + ]
80 + },
81 + "addr": "127.0.0.1:6789/0",
82 + "public_addr": "127.0.0.1:6789/0",
83 + "priority": 0,
84 + "weight": 0,
85 + "crush_location": "{}",
86 + "stats": {
87 + "num_sessions": [
88 + [
89 + 1727428059.43674,
90 + 9
91 + ],
92 + [
93 + 1727428064.436794,
94 + 9
95 + ],
96 + [
97 + 1727428069.4371185,
98 + 9
99 + ],
100 + [
101 + 1727428074.437272,
102 + 9
103 + ],
104 + [
105 + 1727428079.437457,
106 + 9
107 + ],
108 + [
109 + 1727428084.4377377,
110 + 9
111 + ],
112 + [
113 + 1727428089.4380398,
114 + 9
115 + ],
116 + [
117 + 1727428094.4382815,
118 + 9
119 + ],
120 + [
121 + 1727428099.4385583,
122 + 9
123 + ],
124 + [
125 + 1727428104.4388537,
126 + 9
127 + ],
128 + [
129 + 1727428109.439028,
130 + 9
131 + ],
132 + [
133 + 1727428114.439225,
134 + 9
135 + ],
136 + [
137 + 1727428119.4395273,
138 + 9
139 + ],
140 + [
141 + 1727428124.4398105,
142 + 9
143 + ],
144 + [
145 + 1727428129.4401586,
146 + 9
147 + ],
148 + [
149 + 1727428134.4403143,
150 + 9
151 + ],
152 + [
153 + 1727428139.4406898,
154 + 9
155 + ],
156 + [
157 + 1727428144.4407866,
158 + 9
159 + ],
160 + [
161 + 1727428149.4410205,
162 + 9
163 + ],
164 + [
165 + 1727428154.4414103,
166 + 9
167 + ]
168 + ]
169 + }
170 + }
171 + ]
172 + },
173 + "feature_map": {
174 + "mon": [
175 + {
176 + "features": "0x3f01cfbdfffdffff",
177 + "release": "luminous",
178 + "num": 1
179 + }
180 + ],
181 + "osd": [
182 + {
183 + "features": "0x3f01cfbdfffdffff",
184 + "release": "luminous",
185 + "num": 2
186 + }
187 + ],
188 + "client": [
189 + {
190 + "features": "0x3f01cfbdfffdffff",
191 + "release": "luminous",
192 + "num": 4
193 + }
194 + ],
195 + "mgr": [
196 + {
197 + "features": "0x3f01cfbdfffdffff",
198 + "release": "luminous",
199 + "num": 2
200 + }
201 + ]
202 + },
203 + "stretch_mode": false
204 + },
205 + "in_quorum": [
206 + {
207 + "rank": 0,
208 + "name": "pve-deb-work",
209 + "public_addrs": {
210 + "addrvec": [
211 + {
212 + "type": "v2",
213 + "addr": "127.0.0.1:3300",
214 + "nonce": 0
215 + },
216 + {
217 + "type": "v1",
218 + "addr": "127.0.0.1:6789",
219 + "nonce": 0
220 + }
221 + ]
222 + },
223 + "addr": "127.0.0.1:6789/0",
224 + "public_addr": "127.0.0.1:6789/0",
225 + "priority": 0,
226 + "weight": 0,
227 + "crush_location": "{}",
228 + "stats": {
229 + "num_sessions": [
230 + [
231 + 1727428059.43674,
232 + 9
233 + ],
234 + [
235 + 1727428064.436794,
236 + 9
237 + ],
238 + [
239 + 1727428069.4371185,
240 + 9
241 + ],
242 + [
243 + 1727428074.437272,
244 + 9
245 + ],
246 + [
247 + 1727428079.437457,
248 + 9
249 + ],
250 + [
251 + 1727428084.4377377,
252 + 9
253 + ],
254 + [
255 + 1727428089.4380398,
256 + 9
257 + ],
258 + [
259 + 1727428094.4382815,
260 + 9
261 + ],
262 + [
263 + 1727428099.4385583,
264 + 9
265 + ],
266 + [
267 + 1727428104.4388537,
268 + 9
269 + ],
270 + [
271 + 1727428109.439028,
272 + 9
273 + ],
274 + [
275 + 1727428114.439225,
276 + 9
277 + ],
278 + [
279 + 1727428119.4395273,
280 + 9
281 + ],
282 + [
283 + 1727428124.4398105,
284 + 9
285 + ],
286 + [
287 + 1727428129.4401586,
288 + 9
289 + ],
290 + [
291 + 1727428134.4403143,
292 + 9
293 + ],
294 + [
295 + 1727428139.4406898,
296 + 9
297 + ],
298 + [
299 + 1727428144.4407866,
300 + 9
301 + ],
302 + [
303 + 1727428149.4410205,
304 + 9
305 + ],
306 + [
307 + 1727428154.4414103,
308 + 9
309 + ]
310 + ]
311 + }
312 + }
313 + ],
314 + "out_quorum": []
315 +}
src/go/plugin/go.d/modules/ceph/testdata/v16.2.15/api_osd.json new
+930
@@ -0,0 +1,930 @@
1 +[
2 + {
3 + "osd": 0,
4 + "up": 1,
5 + "in": 1,
6 + "weight": 1.0,
7 + "primary_affinity": 1.0,
8 + "last_clean_begin": 0,
9 + "last_clean_end": 0,
10 + "up_from": 16,
11 + "up_thru": 23,
12 + "down_at": 0,
13 + "lost_at": 0,
14 + "public_addrs": {
15 + "addrvec": [
16 + {
17 + "type": "v2",
18 + "nonce": 390161213,
19 + "addr": "127.0.0.1:6802"
20 + },
21 + {
22 + "type": "v1",
23 + "nonce": 390161213,
24 + "addr": "127.0.0.1:6803"
25 + }
26 + ]
27 + },
28 + "cluster_addrs": {
29 + "addrvec": [
30 + {
31 + "type": "v2",
32 + "nonce": 390161213,
33 + "addr": "127.0.0.1:6804"
34 + },
35 + {
36 + "type": "v1",
37 + "nonce": 390161213,
38 + "addr": "127.0.0.1:6805"
39 + }
40 + ]
41 + },
42 + "heartbeat_back_addrs": {
43 + "addrvec": [
44 + {
45 + "type": "v2",
46 + "nonce": 390161213,
47 + "addr": "127.0.0.1:6808"
48 + },
49 + {
50 + "type": "v1",
51 + "nonce": 390161213,
52 + "addr": "127.0.0.1:6809"
53 + }
54 + ]
55 + },
56 + "heartbeat_front_addrs": {
57 + "addrvec": [
58 + {
59 + "type": "v2",
60 + "nonce": 390161213,
61 + "addr": "127.0.0.1:6806"
62 + },
63 + {
64 + "type": "v1",
65 + "nonce": 390161213,
66 + "addr": "127.0.0.1:6807"
67 + }
68 + ]
69 + },
70 + "state": [
71 + "exists",
72 + "up"
73 + ],
74 + "uuid": "f78537db-9b18-4c62-a24f-a4344fc28de7",
75 + "public_addr": "127.0.0.1:6803/390161213",
76 + "cluster_addr": "127.0.0.1:6805/390161213",
77 + "heartbeat_back_addr": "127.0.0.1:6809/390161213",
78 + "heartbeat_front_addr": "127.0.0.1:6807/390161213",
79 + "id": 0,
80 + "osd_stats": {
81 + "osd": 0,
82 + "up_from": 16,
83 + "seq": 68719494425,
84 + "num_pgs": 2,
85 + "num_osds": 1,
86 + "num_per_pool_osds": 1,
87 + "num_per_pool_omap_osds": 1,
88 + "kb": 104853504,
89 + "kb_used": 297392,
90 + "kb_used_data": 296,
91 + "kb_used_omap": 0,
92 + "kb_used_meta": 297088,
93 + "kb_avail": 104556112,
94 + "statfs": {
95 + "total": 107369988096,
96 + "available": 107065458688,
97 + "internally_reserved": 0,
98 + "allocated": 303104,
99 + "data_stored": 115778,
100 + "data_compressed": 0,
101 + "data_compressed_allocated": 0,
102 + "data_compressed_original": 0,
103 + "omap_allocated": 0,
104 + "internal_metadata": 304218112
105 + },
106 + "hb_peers": [
107 + 1
108 + ],
109 + "snap_trim_queue_len": 0,
110 + "num_snap_trimming": 0,
111 + "num_shards_repaired": 0,
112 + "op_queue_age_hist": {
113 + "histogram": [],
114 + "upper_bound": 1
115 + },
116 + "perf_stat": {
117 + "commit_latency_ms": 1.0,
118 + "apply_latency_ms": 1.0,
119 + "commit_latency_ns": 0,
120 + "apply_latency_ns": 0
121 + },
122 + "alerts": []
123 + },
124 + "tree": {
125 + "id": 0,
126 + "device_class": "hdd",
127 + "type": "osd",
128 + "type_id": 0,
129 + "crush_weight": 0.097686767578125,
130 + "depth": 2,
131 + "pool_weights": {},
132 + "exists": 1,
133 + "status": "up",
134 + "reweight": 1.0,
135 + "primary_affinity": 1.0,
136 + "name": "osd.0"
137 + },
138 + "host": {
139 + "id": -3,
140 + "name": "pve-deb-work",
141 + "type": "host",
142 + "type_id": 1,
143 + "pool_weights": {},
144 + "children": [
145 + 1,
146 + 0
147 + ]
148 + },
149 + "stats": {
150 + "op_w": 1.0,
151 + "op_in_bytes": 1.0,
152 + "op_r": 1.0,
153 + "op_out_bytes": 1.0,
154 + "numpg": 2,
155 + "stat_bytes": 107369988096,
156 + "stat_bytes_used": 304529408
157 + },
158 + "stats_history": {
159 + "op_w": [
160 + [
161 + 1727260221.6928742,
162 + 0.0
163 + ],
164 + [
165 + 1727260226.693285,
166 + 0.0
167 + ],
168 + [
169 + 1727260231.693595,
170 + 0.0
171 + ],
172 + [
173 + 1727260236.6938233,
174 + 0.0
175 + ],
176 + [
177 + 1727260241.6942236,
178 + 0.0
179 + ],
180 + [
181 + 1727260246.6945205,
182 + 0.0
183 + ],
184 + [
185 + 1727260251.694739,
186 + 0.0
187 + ],
188 + [
189 + 1727260256.6951063,
190 + 0.0
191 + ],
192 + [
193 + 1727260261.6954763,
194 + 0.0
195 + ],
196 + [
197 + 1727260266.695751,
198 + 0.0
199 + ],
200 + [
201 + 1727260271.6960592,
202 + 0.0
203 + ],
204 + [
205 + 1727260276.6963248,
206 + 0.0
207 + ],
208 + [
209 + 1727260281.6966574,
210 + 0.0
211 + ],
212 + [
213 + 1727260286.696938,
214 + 0.0
215 + ],
216 + [
217 + 1727260291.6973395,
218 + 0.0
219 + ],
220 + [
221 + 1727260296.697657,
222 + 0.0
223 + ],
224 + [
225 + 1727260301.6980677,
226 + 0.0
227 + ],
228 + [
229 + 1727260306.698276,
230 + 0.0
231 + ],
232 + [
233 + 1727260311.6986544,
234 + 0.0
235 + ]
236 + ],
237 + "op_in_bytes": [
238 + [
239 + 1727260221.6928742,
240 + 0.0
241 + ],
242 + [
243 + 1727260226.693285,
244 + 0.0
245 + ],
246 + [
247 + 1727260231.693595,
248 + 0.0
249 + ],
250 + [
251 + 1727260236.6938233,
252 + 0.0
253 + ],
254 + [
255 + 1727260241.6942236,
256 + 0.0
257 + ],
258 + [
259 + 1727260246.6945205,
260 + 0.0
261 + ],
262 + [
263 + 1727260251.694739,
264 + 0.0
265 + ],
266 + [
267 + 1727260256.6951063,
268 + 0.0
269 + ],
270 + [
271 + 1727260261.6954763,
272 + 0.0
273 + ],
274 + [
275 + 1727260266.695751,
276 + 0.0
277 + ],
278 + [
279 + 1727260271.6960592,
280 + 0.0
281 + ],
282 + [
283 + 1727260276.6963248,
284 + 0.0
285 + ],
286 + [
287 + 1727260281.6966574,
288 + 0.0
289 + ],
290 + [
291 + 1727260286.696938,
292 + 0.0
293 + ],
294 + [
295 + 1727260291.6973395,
296 + 0.0
297 + ],
298 + [
299 + 1727260296.697657,
300 + 0.0
301 + ],
302 + [
303 + 1727260301.6980677,
304 + 0.0
305 + ],
306 + [
307 + 1727260306.698276,
308 + 0.0
309 + ],
310 + [
311 + 1727260311.6986544,
312 + 0.0
313 + ]
314 + ],
315 + "op_r": [
316 + [
317 + 1727260221.6928742,
318 + 0.0
319 + ],
320 + [
321 + 1727260226.693285,
322 + 0.0
323 + ],
324 + [
325 + 1727260231.693595,
326 + 0.0
327 + ],
328 + [
329 + 1727260236.6938233,
330 + 0.0
331 + ],
332 + [
333 + 1727260241.6942236,
334 + 0.0
335 + ],
336 + [
337 + 1727260246.6945205,
338 + 0.0
339 + ],
340 + [
341 + 1727260251.694739,
342 + 0.0
343 + ],
344 + [
345 + 1727260256.6951063,
346 + 0.0
347 + ],
348 + [
349 + 1727260261.6954763,
350 + 0.0
351 + ],
352 + [
353 + 1727260266.695751,
354 + 0.0
355 + ],
356 + [
357 + 1727260271.6960592,
358 + 0.0
359 + ],
360 + [
361 + 1727260276.6963248,
362 + 0.0
363 + ],
364 + [
365 + 1727260281.6966574,
366 + 0.0
367 + ],
368 + [
369 + 1727260286.696938,
370 + 0.0
371 + ],
372 + [
373 + 1727260291.6973395,
374 + 0.0
375 + ],
376 + [
377 + 1727260296.697657,
378 + 0.0
379 + ],
380 + [
381 + 1727260301.6980677,
382 + 0.0
383 + ],
384 + [
385 + 1727260306.698276,
386 + 0.0
387 + ],
388 + [
389 + 1727260311.6986544,
390 + 0.0
391 + ]
392 + ],
393 + "op_out_bytes": [
394 + [
395 + 1727260221.6928742,
396 + 0.0
397 + ],
398 + [
399 + 1727260226.693285,
400 + 0.0
401 + ],
402 + [
403 + 1727260231.693595,
404 + 0.0
405 + ],
406 + [
407 + 1727260236.6938233,
408 + 0.0
409 + ],
410 + [
411 + 1727260241.6942236,
412 + 0.0
413 + ],
414 + [
415 + 1727260246.6945205,
416 + 0.0
417 + ],
418 + [
419 + 1727260251.694739,
420 + 0.0
421 + ],
422 + [
423 + 1727260256.6951063,
424 + 0.0
425 + ],
426 + [
427 + 1727260261.6954763,
428 + 0.0
429 + ],
430 + [
431 + 1727260266.695751,
432 + 0.0
433 + ],
434 + [
435 + 1727260271.6960592,
436 + 0.0
437 + ],
438 + [
439 + 1727260276.6963248,
440 + 0.0
441 + ],
442 + [
443 + 1727260281.6966574,
444 + 0.0
445 + ],
446 + [
447 + 1727260286.696938,
448 + 0.0
449 + ],
450 + [
451 + 1727260291.6973395,
452 + 0.0
453 + ],
454 + [
455 + 1727260296.697657,
456 + 0.0
457 + ],
458 + [
459 + 1727260301.6980677,
460 + 0.0
461 + ],
462 + [
463 + 1727260306.698276,
464 + 0.0
465 + ],
466 + [
467 + 1727260311.6986544,
468 + 0.0
469 + ]
470 + ]
471 + },
472 + "operational_status": "working"
473 + },
474 + {
475 + "osd": 1,
476 + "up": 1,
477 + "in": 1,
478 + "weight": 1.0,
479 + "primary_affinity": 1.0,
480 + "last_clean_begin": 0,
481 + "last_clean_end": 0,
482 + "up_from": 22,
483 + "up_thru": 22,
484 + "down_at": 0,
485 + "lost_at": 0,
486 + "public_addrs": {
487 + "addrvec": [
488 + {
489 + "type": "v2",
490 + "nonce": 1173056633,
491 + "addr": "127.0.0.1:6810"
492 + },
493 + {
494 + "type": "v1",
495 + "nonce": 1173056633,
496 + "addr": "127.0.0.1:6811"
497 + }
498 + ]
499 + },
500 + "cluster_addrs": {
501 + "addrvec": [
502 + {
503 + "type": "v2",
504 + "nonce": 1173056633,
505 + "addr": "127.0.0.1:6812"
506 + },
507 + {
508 + "type": "v1",
509 + "nonce": 1173056633,
510 + "addr": "127.0.0.1:6813"
511 + }
512 + ]
513 + },
514 + "heartbeat_back_addrs": {
515 + "addrvec": [
516 + {
517 + "type": "v2",
518 + "nonce": 1173056633,
519 + "addr": "127.0.0.1:6816"
520 + },
521 + {
522 + "type": "v1",
523 + "nonce": 1173056633,
524 + "addr": "127.0.0.1:6817"
525 + }
526 + ]
527 + },
528 + "heartbeat_front_addrs": {
529 + "addrvec": [
530 + {
531 + "type": "v2",
532 + "nonce": 1173056633,
533 + "addr": "127.0.0.1:6814"
534 + },
535 + {
536 + "type": "v1",
537 + "nonce": 1173056633,
538 + "addr": "127.0.0.1:6815"
539 + }
540 + ]
541 + },
542 + "state": [
543 + "exists",
544 + "up"
545 + ],
546 + "uuid": "f5bbbe9d-e85b-419c-af5a-a57e2527cad3",
547 + "public_addr": "127.0.0.1:6811/1173056633",
548 + "cluster_addr": "127.0.0.1:6813/1173056633",
549 + "heartbeat_back_addr": "127.0.0.1:6817/1173056633",
550 + "heartbeat_front_addr": "127.0.0.1:6815/1173056633",
551 + "id": 1,
552 + "osd_stats": {
553 + "osd": 1,
554 + "up_from": 22,
555 + "seq": 94489298171,
556 + "num_pgs": 2,
557 + "num_osds": 1,
558 + "num_per_pool_osds": 1,
559 + "num_per_pool_omap_osds": 1,
560 + "kb": 67104768,
561 + "kb_used": 297392,
562 + "kb_used_data": 296,
563 + "kb_used_omap": 0,
564 + "kb_used_meta": 297088,
565 + "kb_avail": 66807376,
566 + "statfs": {
567 + "total": 68715282432,
568 + "available": 68410753024,
569 + "internally_reserved": 0,
570 + "allocated": 303104,
571 + "data_stored": 115778,
572 + "data_compressed": 0,
573 + "data_compressed_allocated": 0,
574 + "data_compressed_original": 0,
575 + "omap_allocated": 0,
576 + "internal_metadata": 304218112
577 + },
578 + "hb_peers": [
579 + 0
580 + ],
581 + "snap_trim_queue_len": 0,
582 + "num_snap_trimming": 0,
583 + "num_shards_repaired": 0,
584 + "op_queue_age_hist": {
585 + "histogram": [],
586 + "upper_bound": 1
587 + },
588 + "perf_stat": {
589 + "commit_latency_ms": 1.0,
590 + "apply_latency_ms": 1.0,
591 + "commit_latency_ns": 0,
592 + "apply_latency_ns": 0
593 + },
594 + "alerts": []
595 + },
596 + "tree": {
597 + "id": 1,
598 + "device_class": "ssd",
599 + "type": "osd",
600 + "type_id": 0,
601 + "crush_weight": 0.0625,
602 + "depth": 2,
603 + "pool_weights": {},
604 + "exists": 1,
605 + "status": "up",
606 + "reweight": 1.0,
607 + "primary_affinity": 1.0,
608 + "name": "osd.1"
609 + },
610 + "host": {
611 + "id": -3,
612 + "name": "pve-deb-work",
613 + "type": "host",
614 + "type_id": 1,
615 + "pool_weights": {},
616 + "children": [
617 + 1,
618 + 0
619 + ]
620 + },
621 + "stats": {
622 + "op_w": 1.0,
623 + "op_in_bytes": 1.0,
624 + "op_r": 1.0,
625 + "op_out_bytes": 1.0,
626 + "numpg": 2,
627 + "stat_bytes": 68715282432,
628 + "stat_bytes_used": 304529408
629 + },
630 + "stats_history": {
631 + "op_w": [
632 + [
633 + 1727260228.751263,
634 + 0.0
635 + ],
636 + [
637 + 1727260233.7515125,
638 + 0.0
639 + ],
640 + [
641 + 1727260238.7518487,
642 + 0.0
643 + ],
644 + [
645 + 1727260243.752178,
646 + 0.0
647 + ],
648 + [
649 + 1727260248.752556,
650 + 0.0
651 + ],
652 + [
653 + 1727260253.7527573,
654 + 0.0
655 + ],
656 + [
657 + 1727260258.7530267,
658 + 0.0
659 + ],
660 + [
661 + 1727260263.753484,
662 + 0.0
663 + ],
664 + [
665 + 1727260268.753807,
666 + 0.0
667 + ],
668 + [
669 + 1727260273.754063,
670 + 0.0
671 + ],
672 + [
673 + 1727260278.7543082,
674 + 0.0
675 + ],
676 + [
677 + 1727260283.7546039,
678 + 0.0
679 + ],
680 + [
681 + 1727260288.754978,
682 + 0.0
683 + ],
684 + [
685 + 1727260293.7552564,
686 + 0.0
687 + ],
688 + [
689 + 1727260298.755653,
690 + 0.0
691 + ],
692 + [
693 + 1727260303.7559133,
694 + 0.0
695 + ],
696 + [
697 + 1727260308.7562194,
698 + 0.0
699 + ],
700 + [
701 + 1727260313.7565064,
702 + 0.0
703 + ]
704 + ],
705 + "op_in_bytes": [
706 + [
707 + 1727260228.751263,
708 + 0.0
709 + ],
710 + [
711 + 1727260233.7515125,
712 + 0.0
713 + ],
714 + [
715 + 1727260238.7518487,
716 + 0.0
717 + ],
718 + [
719 + 1727260243.752178,
720 + 0.0
721 + ],
722 + [
723 + 1727260248.752556,
724 + 0.0
725 + ],
726 + [
727 + 1727260253.7527573,
728 + 0.0
729 + ],
730 + [
731 + 1727260258.7530267,
732 + 0.0
733 + ],
734 + [
735 + 1727260263.753484,
736 + 0.0
737 + ],
738 + [
739 + 1727260268.753807,
740 + 0.0
741 + ],
742 + [
743 + 1727260273.754063,
744 + 0.0
745 + ],
746 + [
747 + 1727260278.7543082,
748 + 0.0
749 + ],
750 + [
751 + 1727260283.7546039,
752 + 0.0
753 + ],
754 + [
755 + 1727260288.754978,
756 + 0.0
757 + ],
758 + [
759 + 1727260293.7552564,
760 + 0.0
761 + ],
762 + [
763 + 1727260298.755653,
764 + 0.0
765 + ],
766 + [
767 + 1727260303.7559133,
768 + 0.0
769 + ],
770 + [
771 + 1727260308.7562194,
772 + 0.0
773 + ],
774 + [
775 + 1727260313.7565064,
776 + 0.0
777 + ]
778 + ],
779 + "op_r": [
780 + [
781 + 1727260228.751263,
782 + 0.0
783 + ],
784 + [
785 + 1727260233.7515125,
786 + 0.0
787 + ],
788 + [
789 + 1727260238.7518487,
790 + 0.0
791 + ],
792 + [
793 + 1727260243.752178,
794 + 0.0
795 + ],
796 + [
797 + 1727260248.752556,
798 + 0.0
799 + ],
800 + [
801 + 1727260253.7527573,
802 + 0.0
803 + ],
804 + [
805 + 1727260258.7530267,
806 + 0.0
807 + ],
808 + [
809 + 1727260263.753484,
810 + 0.0
811 + ],
812 + [
813 + 1727260268.753807,
814 + 0.0
815 + ],
816 + [
817 + 1727260273.754063,
818 + 0.0
819 + ],
820 + [
821 + 1727260278.7543082,
822 + 0.0
823 + ],
824 + [
825 + 1727260283.7546039,
826 + 0.0
827 + ],
828 + [
829 + 1727260288.754978,
830 + 0.0
831 + ],
832 + [
833 + 1727260293.7552564,
834 + 0.0
835 + ],
836 + [
837 + 1727260298.755653,
838 + 0.0
839 + ],
840 + [
841 + 1727260303.7559133,
842 + 0.0
843 + ],
844 + [
845 + 1727260308.7562194,
846 + 0.0
847 + ],
848 + [
849 + 1727260313.7565064,
850 + 0.0
851 + ]
852 + ],
853 + "op_out_bytes": [
854 + [
855 + 1727260228.751263,
856 + 0.0
857 + ],
858 + [
859 + 1727260233.7515125,
860 + 0.0
861 + ],
862 + [
863 + 1727260238.7518487,
864 + 0.0
865 + ],
866 + [
867 + 1727260243.752178,
868 + 0.0
869 + ],
870 + [
871 + 1727260248.752556,
872 + 0.0
873 + ],
874 + [
875 + 1727260253.7527573,
876 + 0.0
877 + ],
878 + [
879 + 1727260258.7530267,
880 + 0.0
881 + ],
882 + [
883 + 1727260263.753484,
884 + 0.0
885 + ],
886 + [
887 + 1727260268.753807,
888 + 0.0
889 + ],
890 + [
891 + 1727260273.754063,
892 + 0.0
893 + ],
894 + [
895 + 1727260278.7543082,
896 + 0.0
897 + ],
898 + [
899 + 1727260283.7546039,
900 + 0.0
901 + ],
902 + [
903 + 1727260288.754978,
904 + 0.0
905 + ],
906 + [
907 + 1727260293.7552564,
908 + 0.0
909 + ],
910 + [
911 + 1727260298.755653,
912 + 0.0
913 + ],
914 + [
915 + 1727260303.7559133,
916 + 0.0
917 + ],
918 + [
919 + 1727260308.7562194,
920 + 0.0
921 + ],
922 + [
923 + 1727260313.7565064,
924 + 0.0
925 + ]
926 + ]
927 + },
928 + "operational_status": "working"
929 + }
930 +]
src/go/plugin/go.d/modules/ceph/testdata/v16.2.15/api_pool_stats.json new
+1923
@@ -0,0 +1,1923 @@
1 +[
2 + {
3 + "pool": 1,
4 + "pool_name": "mySuperPool",
5 + "flags": 32769,
6 + "flags_names": "hashpspool,creating",
7 + "type": "erasure",
8 + "size": 4,
9 + "min_size": 3,
10 + "crush_rule": "erasure-code",
11 + "peering_crush_bucket_count": 0,
12 + "peering_crush_bucket_target": 0,
13 + "peering_crush_bucket_barrier": 0,
14 + "peering_crush_bucket_mandatory_member": 2147483647,
15 + "object_hash": 2,
16 + "pg_autoscale_mode": "on",
17 + "pg_num": 1,
18 + "pg_placement_num": 1,
19 + "pg_placement_num_target": 32,
20 + "pg_num_target": 32,
21 + "pg_num_pending": 1,
22 + "last_pg_merge_meta": {
23 + "ready_epoch": 0,
24 + "last_epoch_started": 0,
25 + "last_epoch_clean": 0,
26 + "source_pgid": "0.0",
27 + "source_version": "0'0",
28 + "target_version": "0'0"
29 + },
30 + "auid": 0,
31 + "snap_mode": "selfmanaged",
32 + "snap_seq": 0,
33 + "snap_epoch": 0,
34 + "pool_snaps": [],
35 + "quota_max_bytes": 2147483648,
36 + "quota_max_objects": 0,
37 + "tiers": [],
38 + "tier_of": -1,
39 + "read_tier": -1,
40 + "write_tier": -1,
41 + "cache_mode": "none",
42 + "target_max_bytes": 0,
43 + "target_max_objects": 0,
44 + "cache_target_dirty_ratio_micro": 400000,
45 + "cache_target_dirty_high_ratio_micro": 600000,
46 + "cache_target_full_ratio_micro": 800000,
47 + "cache_min_flush_age": 0,
48 + "cache_min_evict_age": 0,
49 + "erasure_code_profile": "default",
50 + "hit_set_params": {
51 + "type": "none"
52 + },
53 + "hit_set_period": 0,
54 + "hit_set_count": 0,
55 + "use_gmt_hitset": true,
56 + "min_read_recency_for_promote": 0,
57 + "min_write_recency_for_promote": 0,
58 + "hit_set_grade_decay_rate": 0,
59 + "hit_set_search_last_n": 0,
60 + "grade_table": [],
61 + "stripe_width": 8192,
62 + "expected_num_objects": 0,
63 + "fast_read": false,
64 + "options": {},
65 + "application_metadata": [],
66 + "create_time": "2024-09-23T17:27:53.650381+0000",
67 + "last_change": "18",
68 + "last_force_op_resend": "0",
69 + "last_force_op_resend_prenautilus": "0",
70 + "last_force_op_resend_preluminous": "0",
71 + "removed_snaps": "[]",
72 + "pg_status": {
73 + "creating+incomplete": 1
74 + },
75 + "stats": {
76 + "stored": {
77 + "latest": 1,
78 + "rate": 0.0,
79 + "rates": [
80 + [
81 + 1727260045.5636568,
82 + 0.0
83 + ],
84 + [
85 + 1727260050.5730257,
86 + 0.0
87 + ],
88 + [
89 + 1727260055.56124,
90 + 0.0
91 + ],
92 + [
93 + 1727260060.564262,
94 + 0.0
95 + ],
96 + [
97 + 1727260065.5657525,
98 + 0.0
99 + ],
100 + [
101 + 1727260070.563676,
102 + 0.0
103 + ],
104 + [
105 + 1727260105.6695807,
106 + 0.0
107 + ],
108 + [
109 + 1727260165.6647935,
110 + 0.0
111 + ],
112 + [
113 + 1727260212.0559795,
114 + 0.0
115 + ]
116 + ]
117 + },
118 + "stored_data": {
119 + "latest": 0,
120 + "rate": 0.0,
121 + "rates": [
122 + [
123 + 1727260045.5636568,
124 + 0.0
125 + ],
126 + [
127 + 1727260050.5730257,
128 + 0.0
129 + ],
130 + [
131 + 1727260055.56124,
132 + 0.0
133 + ],
134 + [
135 + 1727260060.564262,
136 + 0.0
137 + ],
138 + [
139 + 1727260065.5657525,
140 + 0.0
141 + ],
142 + [
143 + 1727260070.563676,
144 + 0.0
145 + ],
146 + [
147 + 1727260105.6695807,
148 + 0.0
149 + ],
150 + [
151 + 1727260165.6647935,
152 + 0.0
153 + ],
154 + [
155 + 1727260212.0559795,
156 + 0.0
157 + ]
158 + ]
159 + },
160 + "stored_omap": {
161 + "latest": 0,
162 + "rate": 0.0,
163 + "rates": [
164 + [
165 + 1727260045.5636568,
166 + 0.0
167 + ],
168 + [
169 + 1727260050.5730257,
170 + 0.0
171 + ],
172 + [
173 + 1727260055.56124,
174 + 0.0
175 + ],
176 + [
177 + 1727260060.564262,
178 + 0.0
179 + ],
180 + [
181 + 1727260065.5657525,
182 + 0.0
183 + ],
184 + [
185 + 1727260070.563676,
186 + 0.0
187 + ],
188 + [
189 + 1727260105.6695807,
190 + 0.0
191 + ],
192 + [
193 + 1727260165.6647935,
194 + 0.0
195 + ],
196 + [
197 + 1727260212.0559795,
198 + 0.0
199 + ]
200 + ]
201 + },
202 + "objects": {
203 + "latest": 1,
204 + "rate": 0.0,
205 + "rates": [
206 + [
207 + 1727260045.5636568,
208 + 0.0
209 + ],
210 + [
211 + 1727260050.5730257,
212 + 0.0
213 + ],
214 + [
215 + 1727260055.56124,
216 + 0.0
217 + ],
218 + [
219 + 1727260060.564262,
220 + 0.0
221 + ],
222 + [
223 + 1727260065.5657525,
224 + 0.0
225 + ],
226 + [
227 + 1727260070.563676,
228 + 0.0
229 + ],
230 + [
231 + 1727260105.6695807,
232 + 0.0
233 + ],
234 + [
235 + 1727260165.6647935,
236 + 0.0
237 + ],
238 + [
239 + 1727260212.0559795,
240 + 0.0
241 + ]
242 + ]
243 + },
244 + "kb_used": {
245 + "latest": 0,
246 + "rate": 0.0,
247 + "rates": [
248 + [
249 + 1727260045.5636568,
250 + 0.0
251 + ],
252 + [
253 + 1727260050.5730257,
254 + 0.0
255 + ],
256 + [
257 + 1727260055.56124,
258 + 0.0
259 + ],
260 + [
261 + 1727260060.564262,
262 + 0.0
263 + ],
264 + [
265 + 1727260065.5657525,
266 + 0.0
267 + ],
268 + [
269 + 1727260070.563676,
270 + 0.0
271 + ],
272 + [
273 + 1727260105.6695807,
274 + 0.0
275 + ],
276 + [
277 + 1727260165.6647935,
278 + 0.0
279 + ],
280 + [
281 + 1727260212.0559795,
282 + 0.0
283 + ]
284 + ]
285 + },
286 + "bytes_used": {
287 + "latest": 1,
288 + "rate": 0.0,
289 + "rates": [
290 + [
291 + 1727260045.5636568,
292 + 0.0
293 + ],
294 + [
295 + 1727260050.5730257,
296 + 0.0
297 + ],
298 + [
299 + 1727260055.56124,
300 + 0.0
301 + ],
302 + [
303 + 1727260060.564262,
304 + 0.0
305 + ],
306 + [
307 + 1727260065.5657525,
308 + 0.0
309 + ],
310 + [
311 + 1727260070.563676,
312 + 0.0
313 + ],
314 + [
315 + 1727260105.6695807,
316 + 0.0
317 + ],
318 + [
319 + 1727260165.6647935,
320 + 0.0
321 + ],
322 + [
323 + 1727260212.0559795,
324 + 0.0
325 + ]
326 + ]
327 + },
328 + "data_bytes_used": {
329 + "latest": 0,
330 + "rate": 0.0,
331 + "rates": [
332 + [
333 + 1727260045.5636568,
334 + 0.0
335 + ],
336 + [
337 + 1727260050.5730257,
338 + 0.0
339 + ],
340 + [
341 + 1727260055.56124,
342 + 0.0
343 + ],
344 + [
345 + 1727260060.564262,
346 + 0.0
347 + ],
348 + [
349 + 1727260065.5657525,
350 + 0.0
351 + ],
352 + [
353 + 1727260070.563676,
354 + 0.0
355 + ],
356 + [
357 + 1727260105.6695807,
358 + 0.0
359 + ],
360 + [
361 + 1727260165.6647935,
362 + 0.0
363 + ],
364 + [
365 + 1727260212.0559795,
366 + 0.0
367 + ]
368 + ]
369 + },
370 + "omap_bytes_used": {
371 + "latest": 0,
372 + "rate": 0.0,
373 + "rates": [
374 + [
375 + 1727260045.5636568,
376 + 0.0
377 + ],
378 + [
379 + 1727260050.5730257,
380 + 0.0
381 + ],
382 + [
383 + 1727260055.56124,
384 + 0.0
385 + ],
386 + [
387 + 1727260060.564262,
388 + 0.0
389 + ],
390 + [
391 + 1727260065.5657525,
392 + 0.0
393 + ],
394 + [
395 + 1727260070.563676,
396 + 0.0
397 + ],
398 + [
399 + 1727260105.6695807,
400 + 0.0
401 + ],
402 + [
403 + 1727260165.6647935,
404 + 0.0
405 + ],
406 + [
407 + 1727260212.0559795,
408 + 0.0
409 + ]
410 + ]
411 + },
412 + "percent_used": {
413 + "latest": 1.0,
414 + "rate": 0.0,
415 + "rates": [
416 + [
417 + 1727260045.5636568,
418 + 0.0
419 + ],
420 + [
421 + 1727260050.5730257,
422 + 0.0
423 + ],
424 + [
425 + 1727260055.56124,
426 + 0.0
427 + ],
428 + [
429 + 1727260060.564262,
430 + 0.0
431 + ],
432 + [
433 + 1727260065.5657525,
434 + 0.0
435 + ],
436 + [
437 + 1727260070.563676,
438 + 0.0
439 + ],
440 + [
441 + 1727260105.6695807,
442 + 0.0
443 + ],
444 + [
445 + 1727260165.6647935,
446 + 0.0
447 + ],
448 + [
449 + 1727260212.0559795,
450 + 0.0
451 + ]
452 + ]
453 + },
454 + "max_avail": {
455 + "latest": 83265085440,
456 + "rate": 0.0,
457 + "rates": [
458 + [
459 + 1727260045.5636568,
460 + 0.0
461 + ],
462 + [
463 + 1727260050.5730257,
464 + 0.0
465 + ],
466 + [
467 + 1727260055.56124,
468 + 0.0
469 + ],
470 + [
471 + 1727260060.564262,
472 + 0.0
473 + ],
474 + [
475 + 1727260065.5657525,
476 + 0.0
477 + ],
478 + [
479 + 1727260070.563676,
480 + 0.0
481 + ],
482 + [
483 + 1727260105.6695807,
484 + 0.0
485 + ],
486 + [
487 + 1727260165.6647935,
488 + 0.0
489 + ],
490 + [
491 + 1727260212.0559795,
492 + 0.0
493 + ]
494 + ]
495 + },
496 + "quota_objects": {
497 + "latest": 0,
498 + "rate": 0.0,
499 + "rates": [
500 + [
501 + 1727260045.5636568,
502 + 0.0
503 + ],
504 + [
505 + 1727260050.5730257,
506 + 0.0
507 + ],
508 + [
509 + 1727260055.56124,
510 + 0.0
511 + ],
512 + [
513 + 1727260060.564262,
514 + 0.0
515 + ],
516 + [
517 + 1727260065.5657525,
518 + 0.0
519 + ],
520 + [
521 + 1727260070.563676,
522 + 0.0
523 + ],
524 + [
525 + 1727260105.6695807,
526 + 0.0
527 + ],
528 + [
529 + 1727260165.6647935,
530 + 0.0
531 + ],
532 + [
533 + 1727260212.0559795,
534 + 0.0
535 + ]
536 + ]
537 + },
538 + "quota_bytes": {
539 + "latest": 2147483648,
540 + "rate": 0.0,
541 + "rates": [
542 + [
543 + 1727260045.5636568,
544 + 0.0
545 + ],
546 + [
547 + 1727260050.5730257,
548 + 0.0
549 + ],
550 + [
551 + 1727260055.56124,
552 + 0.0
553 + ],
554 + [
555 + 1727260060.564262,
556 + 0.0
557 + ],
558 + [
559 + 1727260065.5657525,
560 + 0.0
561 + ],
562 + [
563 + 1727260070.563676,
564 + 0.0
565 + ],
566 + [
567 + 1727260105.6695807,
568 + 0.0
569 + ],
570 + [
571 + 1727260165.6647935,
572 + 0.0
573 + ],
574 + [
575 + 1727260212.0559795,
576 + 0.0
577 + ]
578 + ]
579 + },
580 + "dirty": {
581 + "latest": 0,
582 + "rate": 0.0,
583 + "rates": [
584 + [
585 + 1727260045.5636568,
586 + 0.0
587 + ],
588 + [
589 + 1727260050.5730257,
590 + 0.0
591 + ],
592 + [
593 + 1727260055.56124,
594 + 0.0
595 + ],
596 + [
597 + 1727260060.564262,
598 + 0.0
599 + ],
600 + [
601 + 1727260065.5657525,
602 + 0.0
603 + ],
604 + [
605 + 1727260070.563676,
606 + 0.0
607 + ],
608 + [
609 + 1727260105.6695807,
610 + 0.0
611 + ],
612 + [
613 + 1727260165.6647935,
614 + 0.0
615 + ],
616 + [
617 + 1727260212.0559795,
618 + 0.0
619 + ]
620 + ]
621 + },
622 + "rd": {
623 + "latest": 1,
624 + "rate": 0.0,
625 + "rates": [
626 + [
627 + 1727260045.5636568,
628 + 0.0
629 + ],
630 + [
631 + 1727260050.5730257,
632 + 0.0
633 + ],
634 + [
635 + 1727260055.56124,
636 + 0.0
637 + ],
638 + [
639 + 1727260060.564262,
640 + 0.0
641 + ],
642 + [
643 + 1727260065.5657525,
644 + 0.0
645 + ],
646 + [
647 + 1727260070.563676,
648 + 0.0
649 + ],
650 + [
651 + 1727260105.6695807,
652 + 0.0
653 + ],
654 + [
655 + 1727260165.6647935,
656 + 0.0
657 + ],
658 + [
659 + 1727260212.0559795,
660 + 0.0
661 + ]
662 + ]
663 + },
664 + "rd_bytes": {
665 + "latest": 1,
666 + "rate": 0.0,
667 + "rates": [
668 + [
669 + 1727260045.5636568,
670 + 0.0
671 + ],
672 + [
673 + 1727260050.5730257,
674 + 0.0
675 + ],
676 + [
677 + 1727260055.56124,
678 + 0.0
679 + ],
680 + [
681 + 1727260060.564262,
682 + 0.0
683 + ],
684 + [
685 + 1727260065.5657525,
686 + 0.0
687 + ],
688 + [
689 + 1727260070.563676,
690 + 0.0
691 + ],
692 + [
693 + 1727260105.6695807,
694 + 0.0
695 + ],
696 + [
697 + 1727260165.6647935,
698 + 0.0
699 + ],
700 + [
701 + 1727260212.0559795,
702 + 0.0
703 + ]
704 + ]
705 + },
706 + "wr": {
707 + "latest": 1,
708 + "rate": 0.0,
709 + "rates": [
710 + [
711 + 1727260045.5636568,
712 + 0.0
713 + ],
714 + [
715 + 1727260050.5730257,
716 + 0.0
717 + ],
718 + [
719 + 1727260055.56124,
720 + 0.0
721 + ],
722 + [
723 + 1727260060.564262,
724 + 0.0
725 + ],
726 + [
727 + 1727260065.5657525,
728 + 0.0
729 + ],
730 + [
731 + 1727260070.563676,
732 + 0.0
733 + ],
734 + [
735 + 1727260105.6695807,
736 + 0.0
737 + ],
738 + [
739 + 1727260165.6647935,
740 + 0.0
741 + ],
742 + [
743 + 1727260212.0559795,
744 + 0.0
745 + ]
746 + ]
747 + },
748 + "wr_bytes": {
749 + "latest": 1,
750 + "rate": 0.0,
751 + "rates": [
752 + [
753 + 1727260045.5636568,
754 + 0.0
755 + ],
756 + [
757 + 1727260050.5730257,
758 + 0.0
759 + ],
760 + [
761 + 1727260055.56124,
762 + 0.0
763 + ],
764 + [
765 + 1727260060.564262,
766 + 0.0
767 + ],
768 + [
769 + 1727260065.5657525,
770 + 0.0
771 + ],
772 + [
773 + 1727260070.563676,
774 + 0.0
775 + ],
776 + [
777 + 1727260105.6695807,
778 + 0.0
779 + ],
780 + [
781 + 1727260165.6647935,
782 + 0.0
783 + ],
784 + [
785 + 1727260212.0559795,
786 + 0.0
787 + ]
788 + ]
789 + },
790 + "compress_bytes_used": {
791 + "latest": 0,
792 + "rate": 0.0,
793 + "rates": [
794 + [
795 + 1727260045.5636568,
796 + 0.0
797 + ],
798 + [
799 + 1727260050.5730257,
800 + 0.0
801 + ],
802 + [
803 + 1727260055.56124,
804 + 0.0
805 + ],
806 + [
807 + 1727260060.564262,
808 + 0.0
809 + ],
810 + [
811 + 1727260065.5657525,
812 + 0.0
813 + ],
814 + [
815 + 1727260070.563676,
816 + 0.0
817 + ],
818 + [
819 + 1727260105.6695807,
820 + 0.0
821 + ],
822 + [
823 + 1727260165.6647935,
824 + 0.0
825 + ],
826 + [
827 + 1727260212.0559795,
828 + 0.0
829 + ]
830 + ]
831 + },
832 + "compress_under_bytes": {
833 + "latest": 0,
834 + "rate": 0.0,
835 + "rates": [
836 + [
837 + 1727260045.5636568,
838 + 0.0
839 + ],
840 + [
841 + 1727260050.5730257,
842 + 0.0
843 + ],
844 + [
845 + 1727260055.56124,
846 + 0.0
847 + ],
848 + [
849 + 1727260060.564262,
850 + 0.0
851 + ],
852 + [
853 + 1727260065.5657525,
854 + 0.0
855 + ],
856 + [
857 + 1727260070.563676,
858 + 0.0
859 + ],
860 + [
861 + 1727260105.6695807,
862 + 0.0
863 + ],
864 + [
865 + 1727260165.6647935,
866 + 0.0
867 + ],
868 + [
869 + 1727260212.0559795,
870 + 0.0
871 + ]
872 + ]
873 + },
874 + "stored_raw": {
875 + "latest": 0,
876 + "rate": 0.0,
877 + "rates": [
878 + [
879 + 1727260045.5636568,
880 + 0.0
881 + ],
882 + [
883 + 1727260050.5730257,
884 + 0.0
885 + ],
886 + [
887 + 1727260055.56124,
888 + 0.0
889 + ],
890 + [
891 + 1727260060.564262,
892 + 0.0
893 + ],
894 + [
895 + 1727260065.5657525,
896 + 0.0
897 + ],
898 + [
899 + 1727260070.563676,
900 + 0.0
901 + ],
902 + [
903 + 1727260105.6695807,
904 + 0.0
905 + ],
906 + [
907 + 1727260165.6647935,
908 + 0.0
909 + ],
910 + [
911 + 1727260212.0559795,
912 + 0.0
913 + ]
914 + ]
915 + },
916 + "avail_raw": {
917 + "latest": 166530172973,
918 + "rate": 0.0,
919 + "rates": [
920 + [
921 + 1727260045.5636568,
922 + 0.0
923 + ],
924 + [
925 + 1727260050.5730257,
926 + 0.0
927 + ],
928 + [
929 + 1727260055.56124,
930 + 0.0
931 + ],
932 + [
933 + 1727260060.564262,
934 + 0.0
935 + ],
936 + [
937 + 1727260065.5657525,
938 + 0.0
939 + ],
940 + [
941 + 1727260070.563676,
942 + 0.0
943 + ],
944 + [
945 + 1727260105.6695807,
946 + 0.0
947 + ],
948 + [
949 + 1727260165.6647935,
950 + 0.0
951 + ],
952 + [
953 + 1727260212.0559795,
954 + 0.0
955 + ]
956 + ]
957 + }
958 + }
959 + },
960 + {
961 + "pool": 2,
962 + "pool_name": "device_health_metrics",
963 + "flags": 1,
964 + "flags_names": "hashpspool",
965 + "type": "replicated",
966 + "size": 2,
967 + "min_size": 1,
968 + "crush_rule": "replicated_rule",
969 + "peering_crush_bucket_count": 0,
970 + "peering_crush_bucket_target": 0,
971 + "peering_crush_bucket_barrier": 0,
972 + "peering_crush_bucket_mandatory_member": 2147483647,
973 + "object_hash": 2,
974 + "pg_autoscale_mode": "on",
975 + "pg_num": 1,
976 + "pg_placement_num": 1,
977 + "pg_placement_num_target": 1,
978 + "pg_num_target": 1,
979 + "pg_num_pending": 1,
980 + "last_pg_merge_meta": {
981 + "ready_epoch": 0,
982 + "last_epoch_started": 0,
983 + "last_epoch_clean": 0,
984 + "source_pgid": "0.0",
985 + "source_version": "0'0",
986 + "target_version": "0'0"
987 + },
988 + "auid": 0,
989 + "snap_mode": "selfmanaged",
990 + "snap_seq": 0,
991 + "snap_epoch": 0,
992 + "pool_snaps": [],
993 + "quota_max_bytes": 0,
994 + "quota_max_objects": 0,
995 + "tiers": [],
996 + "tier_of": -1,
997 + "read_tier": -1,
998 + "write_tier": -1,
999 + "cache_mode": "none",
1000 + "target_max_bytes": 0,
1001 + "target_max_objects": 0,
1002 + "cache_target_dirty_ratio_micro": 400000,
1003 + "cache_target_dirty_high_ratio_micro": 600000,
1004 + "cache_target_full_ratio_micro": 800000,
1005 + "cache_min_flush_age": 0,
1006 + "cache_min_evict_age": 0,
1007 + "erasure_code_profile": "",
1008 + "hit_set_params": {
1009 + "type": "none"
1010 + },
1011 + "hit_set_period": 0,
1012 + "hit_set_count": 0,
1013 + "use_gmt_hitset": true,
1014 + "min_read_recency_for_promote": 0,
1015 + "min_write_recency_for_promote": 0,
1016 + "hit_set_grade_decay_rate": 0,
1017 + "hit_set_search_last_n": 0,
1018 + "grade_table": [],
1019 + "stripe_width": 0,
1020 + "expected_num_objects": 0,
1021 + "fast_read": false,
1022 + "options": {
1023 + "pg_num_max": 32,
1024 + "pg_num_min": 1
1025 + },
1026 + "application_metadata": [
1027 + "mgr_devicehealth"
1028 + ],
1029 + "create_time": "2024-09-24T10:00:22.967240+0000",
1030 + "last_change": "25",
1031 + "last_force_op_resend": "0",
1032 + "last_force_op_resend_prenautilus": "0",
1033 + "last_force_op_resend_preluminous": "0",
1034 + "removed_snaps": "[]",
1035 + "pg_status": {
1036 + "active+clean": 1
1037 + },
1038 + "stats": {
1039 + "stored": {
1040 + "latest": 1,
1041 + "rate": 0.0,
1042 + "rates": [
1043 + [
1044 + 1727260045.5636568,
1045 + 0.0
1046 + ],
1047 + [
1048 + 1727260050.5730257,
1049 + 0.0
1050 + ],
1051 + [
1052 + 1727260055.56124,
1053 + 0.0
1054 + ],
1055 + [
1056 + 1727260060.564262,
1057 + 0.0
1058 + ],
1059 + [
1060 + 1727260065.5657525,
1061 + 0.0
1062 + ],
1063 + [
1064 + 1727260070.563676,
1065 + 0.0
1066 + ],
1067 + [
1068 + 1727260105.6695807,
1069 + 0.0
1070 + ],
1071 + [
1072 + 1727260165.6647935,
1073 + 0.0
1074 + ],
1075 + [
1076 + 1727260212.0559795,
1077 + 0.0
1078 + ]
1079 + ]
1080 + },
1081 + "stored_data": {
1082 + "latest": 1,
1083 + "rate": 0.0,
1084 + "rates": [
1085 + [
1086 + 1727260045.5636568,
1087 + 0.0
1088 + ],
1089 + [
1090 + 1727260050.5730257,
1091 + 0.0
1092 + ],
1093 + [
1094 + 1727260055.56124,
1095 + 0.0
1096 + ],
1097 + [
1098 + 1727260060.564262,
1099 + 0.0
1100 + ],
1101 + [
1102 + 1727260065.5657525,
1103 + 0.0
1104 + ],
1105 + [
1106 + 1727260070.563676,
1107 + 0.0
1108 + ],
1109 + [
1110 + 1727260105.6695807,
1111 + 0.0
1112 + ],
1113 + [
1114 + 1727260165.6647935,
1115 + 0.0
1116 + ],
1117 + [
1118 + 1727260212.0559795,
1119 + 0.0
1120 + ]
1121 + ]
1122 + },
1123 + "stored_omap": {
1124 + "latest": 0,
1125 + "rate": 0.0,
1126 + "rates": [
1127 + [
1128 + 1727260045.5636568,
1129 + 0.0
1130 + ],
1131 + [
1132 + 1727260050.5730257,
1133 + 0.0
1134 + ],
1135 + [
1136 + 1727260055.56124,
1137 + 0.0
1138 + ],
1139 + [
1140 + 1727260060.564262,
1141 + 0.0
1142 + ],
1143 + [
1144 + 1727260065.5657525,
1145 + 0.0
1146 + ],
1147 + [
1148 + 1727260070.563676,
1149 + 0.0
1150 + ],
1151 + [
1152 + 1727260105.6695807,
1153 + 0.0
1154 + ],
1155 + [
1156 + 1727260165.6647935,
1157 + 0.0
1158 + ],
1159 + [
1160 + 1727260212.0559795,
1161 + 0.0
1162 + ]
1163 + ]
1164 + },
1165 + "objects": {
1166 + "latest": 3,
1167 + "rate": 0.0,
1168 + "rates": [
1169 + [
1170 + 1727260045.5636568,
1171 + 0.0
1172 + ],
1173 + [
1174 + 1727260050.5730257,
1175 + 0.0
1176 + ],
1177 + [
1178 + 1727260055.56124,
1179 + 0.0
1180 + ],
1181 + [
1182 + 1727260060.564262,
1183 + 0.0
1184 + ],
1185 + [
1186 + 1727260065.5657525,
1187 + 0.0
1188 + ],
1189 + [
1190 + 1727260070.563676,
1191 + 0.0
1192 + ],
1193 + [
1194 + 1727260105.6695807,
1195 + 0.0
1196 + ],
1197 + [
1198 + 1727260165.6647935,
1199 + 0.0
1200 + ],
1201 + [
1202 + 1727260212.0559795,
1203 + 0.0
1204 + ]
1205 + ]
1206 + },
1207 + "kb_used": {
1208 + "latest": 0,
1209 + "rate": 0.0,
1210 + "rates": [
1211 + [
1212 + 1727260045.5636568,
1213 + 0.0
1214 + ],
1215 + [
1216 + 1727260050.5730257,
1217 + 0.0
1218 + ],
1219 + [
1220 + 1727260055.56124,
1221 + 0.0
1222 + ],
1223 + [
1224 + 1727260060.564262,
1225 + 0.0
1226 + ],
1227 + [
1228 + 1727260065.5657525,
1229 + 0.0
1230 + ],
1231 + [
1232 + 1727260070.563676,
1233 + 0.0
1234 + ],
1235 + [
1236 + 1727260105.6695807,
1237 + 0.0
1238 + ],
1239 + [
1240 + 1727260165.6647935,
1241 + 0.0
1242 + ],
1243 + [
1244 + 1727260212.0559795,
1245 + 0.0
1246 + ]
1247 + ]
1248 + },
1249 + "bytes_used": {
1250 + "latest": 1,
1251 + "rate": 0.0,
1252 + "rates": [
1253 + [
1254 + 1727260045.5636568,
1255 + 0.0
1256 + ],
1257 + [
1258 + 1727260050.5730257,
1259 + 0.0
1260 + ],
1261 + [
1262 + 1727260055.56124,
1263 + 0.0
1264 + ],
1265 + [
1266 + 1727260060.564262,
1267 + 0.0
1268 + ],
1269 + [
1270 + 1727260065.5657525,
1271 + 0.0
1272 + ],
1273 + [
1274 + 1727260070.563676,
1275 + 0.0
1276 + ],
1277 + [
1278 + 1727260105.6695807,
1279 + 0.0
1280 + ],
1281 + [
1282 + 1727260165.6647935,
1283 + 0.0
1284 + ],
1285 + [
1286 + 1727260212.0559795,
1287 + 0.0
1288 + ]
1289 + ]
1290 + },
1291 + "data_bytes_used": {
1292 + "latest": 0,
1293 + "rate": 0.0,
1294 + "rates": [
1295 + [
1296 + 1727260045.5636568,
1297 + 0.0
1298 + ],
1299 + [
1300 + 1727260050.5730257,
1301 + 0.0
1302 + ],
1303 + [
1304 + 1727260055.56124,
1305 + 0.0
1306 + ],
1307 + [
1308 + 1727260060.564262,
1309 + 0.0
1310 + ],
1311 + [
1312 + 1727260065.5657525,
1313 + 0.0
1314 + ],
1315 + [
1316 + 1727260070.563676,
1317 + 0.0
1318 + ],
1319 + [
1320 + 1727260105.6695807,
1321 + 0.0
1322 + ],
1323 + [
1324 + 1727260165.6647935,
1325 + 0.0
1326 + ],
1327 + [
1328 + 1727260212.0559795,
1329 + 0.0
1330 + ]
1331 + ]
1332 + },
1333 + "omap_bytes_used": {
1334 + "latest": 0,
1335 + "rate": 0.0,
1336 + "rates": [
1337 + [
1338 + 1727260045.5636568,
1339 + 0.0
1340 + ],
1341 + [
1342 + 1727260050.5730257,
1343 + 0.0
1344 + ],
1345 + [
1346 + 1727260055.56124,
1347 + 0.0
1348 + ],
1349 + [
1350 + 1727260060.564262,
1351 + 0.0
1352 + ],
1353 + [
1354 + 1727260065.5657525,
1355 + 0.0
1356 + ],
1357 + [
1358 + 1727260070.563676,
1359 + 0.0
1360 + ],
1361 + [
1362 + 1727260105.6695807,
1363 + 0.0
1364 + ],
1365 + [
1366 + 1727260165.6647935,
1367 + 0.0
1368 + ],
1369 + [
1370 + 1727260212.0559795,
1371 + 0.0
1372 + ]
1373 + ]
1374 + },
1375 + "percent_used": {
1376 + "latest": 1.0,
1377 + "rate": 0.0,
1378 + "rates": [
1379 + [
1380 + 1727260045.5636568,
1381 + 0.0
1382 + ],
1383 + [
1384 + 1727260050.5730257,
1385 + 0.0
1386 + ],
1387 + [
1388 + 1727260055.56124,
1389 + 0.0
1390 + ],
1391 + [
1392 + 1727260060.564262,
1393 + 0.0
1394 + ],
1395 + [
1396 + 1727260065.5657525,
1397 + 0.0
1398 + ],
1399 + [
1400 + 1727260070.563676,
1401 + 0.0
1402 + ],
1403 + [
1404 + 1727260105.6695807,
1405 + 0.0
1406 + ],
1407 + [
1408 + 1727260165.6647935,
1409 + 0.0
1410 + ],
1411 + [
1412 + 1727260212.0559795,
1413 + 0.0
1414 + ]
1415 + ]
1416 + },
1417 + "max_avail": {
1418 + "latest": 83265085440,
1419 + "rate": 0.0,
1420 + "rates": [
1421 + [
1422 + 1727260045.5636568,
1423 + 0.0
1424 + ],
1425 + [
1426 + 1727260050.5730257,
1427 + 0.0
1428 + ],
1429 + [
1430 + 1727260055.56124,
1431 + 0.0
1432 + ],
1433 + [
1434 + 1727260060.564262,
1435 + 0.0
1436 + ],
1437 + [
1438 + 1727260065.5657525,
1439 + 0.0
1440 + ],
1441 + [
1442 + 1727260070.563676,
1443 + 0.0
1444 + ],
1445 + [
1446 + 1727260105.6695807,
1447 + 0.0
1448 + ],
1449 + [
1450 + 1727260165.6647935,
1451 + 0.0
1452 + ],
1453 + [
1454 + 1727260212.0559795,
1455 + 0.0
1456 + ]
1457 + ]
1458 + },
1459 + "quota_objects": {
1460 + "latest": 0,
1461 + "rate": 0.0,
1462 + "rates": [
1463 + [
1464 + 1727260045.5636568,
1465 + 0.0
1466 + ],
1467 + [
1468 + 1727260050.5730257,
1469 + 0.0
1470 + ],
1471 + [
1472 + 1727260055.56124,
1473 + 0.0
1474 + ],
1475 + [
1476 + 1727260060.564262,
1477 + 0.0
1478 + ],
1479 + [
1480 + 1727260065.5657525,
1481 + 0.0
1482 + ],
1483 + [
1484 + 1727260070.563676,
1485 + 0.0
1486 + ],
1487 + [
1488 + 1727260105.6695807,
1489 + 0.0
1490 + ],
1491 + [
1492 + 1727260165.6647935,
1493 + 0.0
1494 + ],
1495 + [
1496 + 1727260212.0559795,
1497 + 0.0
1498 + ]
1499 + ]
1500 + },
1501 + "quota_bytes": {
1502 + "latest": 0,
1503 + "rate": 0.0,
1504 + "rates": [
1505 + [
1506 + 1727260045.5636568,
1507 + 0.0
1508 + ],
1509 + [
1510 + 1727260050.5730257,
1511 + 0.0
1512 + ],
1513 + [
1514 + 1727260055.56124,
1515 + 0.0
1516 + ],
1517 + [
1518 + 1727260060.564262,
1519 + 0.0
1520 + ],
1521 + [
1522 + 1727260065.5657525,
1523 + 0.0
1524 + ],
1525 + [
1526 + 1727260070.563676,
1527 + 0.0
1528 + ],
1529 + [
1530 + 1727260105.6695807,
1531 + 0.0
1532 + ],
1533 + [
1534 + 1727260165.6647935,
1535 + 0.0
1536 + ],
1537 + [
1538 + 1727260212.0559795,
1539 + 0.0
1540 + ]
1541 + ]
1542 + },
1543 + "dirty": {
1544 + "latest": 0,
1545 + "rate": 0.0,
1546 + "rates": [
1547 + [
1548 + 1727260045.5636568,
1549 + 0.0
1550 + ],
1551 + [
1552 + 1727260050.5730257,
1553 + 0.0
1554 + ],
1555 + [
1556 + 1727260055.56124,
1557 + 0.0
1558 + ],
1559 + [
1560 + 1727260060.564262,
1561 + 0.0
1562 + ],
1563 + [
1564 + 1727260065.5657525,
1565 + 0.0
1566 + ],
1567 + [
1568 + 1727260070.563676,
1569 + 0.0
1570 + ],
1571 + [
1572 + 1727260105.6695807,
1573 + 0.0
1574 + ],
1575 + [
1576 + 1727260165.6647935,
1577 + 0.0
1578 + ],
1579 + [
1580 + 1727260212.0559795,
1581 + 0.0
1582 + ]
1583 + ]
1584 + },
1585 + "rd": {
1586 + "latest": 1,
1587 + "rate": 0.0,
1588 + "rates": [
1589 + [
1590 + 1727260045.5636568,
1591 + 0.0
1592 + ],
1593 + [
1594 + 1727260050.5730257,
1595 + 0.0
1596 + ],
1597 + [
1598 + 1727260055.56124,
1599 + 0.0
1600 + ],
1601 + [
1602 + 1727260060.564262,
1603 + 0.0
1604 + ],
1605 + [
1606 + 1727260065.5657525,
1607 + 0.0
1608 + ],
1609 + [
1610 + 1727260070.563676,
1611 + 0.0
1612 + ],
1613 + [
1614 + 1727260105.6695807,
1615 + 0.0
1616 + ],
1617 + [
1618 + 1727260165.6647935,
1619 + 0.0
1620 + ],
1621 + [
1622 + 1727260212.0559795,
1623 + 0.0
1624 + ]
1625 + ]
1626 + },
1627 + "rd_bytes": {
1628 + "latest": 1,
1629 + "rate": 0.0,
1630 + "rates": [
1631 + [
1632 + 1727260045.5636568,
1633 + 0.0
1634 + ],
1635 + [
1636 + 1727260050.5730257,
1637 + 0.0
1638 + ],
1639 + [
1640 + 1727260055.56124,
1641 + 0.0
1642 + ],
1643 + [
1644 + 1727260060.564262,
1645 + 0.0
1646 + ],
1647 + [
1648 + 1727260065.5657525,
1649 + 0.0
1650 + ],
1651 + [
1652 + 1727260070.563676,
1653 + 0.0
1654 + ],
1655 + [
1656 + 1727260105.6695807,
1657 + 0.0
1658 + ],
1659 + [
1660 + 1727260165.6647935,
1661 + 0.0
1662 + ],
1663 + [
1664 + 1727260212.0559795,
1665 + 0.0
1666 + ]
1667 + ]
1668 + },
1669 + "wr": {
1670 + "latest": 3,
1671 + "rate": 0.0,
1672 + "rates": [
1673 + [
1674 + 1727260045.5636568,
1675 + 0.0
1676 + ],
1677 + [
1678 + 1727260050.5730257,
1679 + 0.0
1680 + ],
1681 + [
1682 + 1727260055.56124,
1683 + 0.0
1684 + ],
1685 + [
1686 + 1727260060.564262,
1687 + 0.0
1688 + ],
1689 + [
1690 + 1727260065.5657525,
1691 + 0.0
1692 + ],
1693 + [
1694 + 1727260070.563676,
1695 + 0.0
1696 + ],
1697 + [
1698 + 1727260105.6695807,
1699 + 0.0
1700 + ],
1701 + [
1702 + 1727260165.6647935,
1703 + 0.0
1704 + ],
1705 + [
1706 + 1727260212.0559795,
1707 + 0.0
1708 + ]
1709 + ]
1710 + },
1711 + "wr_bytes": {
1712 + "latest": 6144,
1713 + "rate": 0.0,
1714 + "rates": [
1715 + [
1716 + 1727260045.5636568,
1717 + 0.0
1718 + ],
1719 + [
1720 + 1727260050.5730257,
1721 + 0.0
1722 + ],
1723 + [
1724 + 1727260055.56124,
1725 + 0.0
1726 + ],
1727 + [
1728 + 1727260060.564262,
1729 + 0.0
1730 + ],
1731 + [
1732 + 1727260065.5657525,
1733 + 0.0
1734 + ],
1735 + [
1736 + 1727260070.563676,
1737 + 0.0
1738 + ],
1739 + [
1740 + 1727260105.6695807,
1741 + 0.0
1742 + ],
1743 + [
1744 + 1727260165.6647935,
1745 + 0.0
1746 + ],
1747 + [
1748 + 1727260212.0559795,
1749 + 0.0
1750 + ]
1751 + ]
1752 + },
1753 + "compress_bytes_used": {
1754 + "latest": 0,
1755 + "rate": 0.0,
1756 + "rates": [
1757 + [
1758 + 1727260045.5636568,
1759 + 0.0
1760 + ],
1761 + [
1762 + 1727260050.5730257,
1763 + 0.0
1764 + ],
1765 + [
1766 + 1727260055.56124,
1767 + 0.0
1768 + ],
1769 + [
1770 + 1727260060.564262,
1771 + 0.0
1772 + ],
1773 + [
1774 + 1727260065.5657525,
1775 + 0.0
1776 + ],
1777 + [
1778 + 1727260070.563676,
1779 + 0.0
1780 + ],
1781 + [
1782 + 1727260105.6695807,
1783 + 0.0
1784 + ],
1785 + [
1786 + 1727260165.6647935,
1787 + 0.0
1788 + ],
1789 + [
1790 + 1727260212.0559795,
1791 + 0.0
1792 + ]
1793 + ]
1794 + },
1795 + "compress_under_bytes": {
1796 + "latest": 0,
1797 + "rate": 0.0,
1798 + "rates": [
1799 + [
1800 + 1727260045.5636568,
1801 + 0.0
1802 + ],
1803 + [
1804 + 1727260050.5730257,
1805 + 0.0
1806 + ],
1807 + [
1808 + 1727260055.56124,
1809 + 0.0
1810 + ],
1811 + [
1812 + 1727260060.564262,
1813 + 0.0
1814 + ],
1815 + [
1816 + 1727260065.5657525,
1817 + 0.0
1818 + ],
1819 + [
1820 + 1727260070.563676,
1821 + 0.0
1822 + ],
1823 + [
1824 + 1727260105.6695807,
1825 + 0.0
1826 + ],
1827 + [
1828 + 1727260165.6647935,
1829 + 0.0
1830 + ],
1831 + [
1832 + 1727260212.0559795,
1833 + 0.0
1834 + ]
1835 + ]
1836 + },
1837 + "stored_raw": {
1838 + "latest": 0,
1839 + "rate": 0.0,
1840 + "rates": [
1841 + [
1842 + 1727260045.5636568,
1843 + 0.0
1844 + ],
1845 + [
1846 + 1727260050.5730257,
1847 + 0.0
1848 + ],
1849 + [
1850 + 1727260055.56124,
1851 + 0.0
1852 + ],
1853 + [
1854 + 1727260060.564262,
1855 + 0.0
1856 + ],
1857 + [
1858 + 1727260065.5657525,
1859 + 0.0
1860 + ],
1861 + [
1862 + 1727260070.563676,
1863 + 0.0
1864 + ],
1865 + [
1866 + 1727260105.6695807,
1867 + 0.0
1868 + ],
1869 + [
1870 + 1727260165.6647935,
1871 + 0.0
1872 + ],
1873 + [
1874 + 1727260212.0559795,
1875 + 0.0
1876 + ]
1877 + ]
1878 + },
1879 + "avail_raw": {
1880 + "latest": 166530172973,
1881 + "rate": 0.0,
1882 + "rates": [
1883 + [
1884 + 1727260045.5636568,
1885 + 0.0
1886 + ],
1887 + [
1888 + 1727260050.5730257,
1889 + 0.0
1890 + ],
1891 + [
1892 + 1727260055.56124,
1893 + 0.0
1894 + ],
1895 + [
1896 + 1727260060.564262,
1897 + 0.0
1898 + ],
1899 + [
1900 + 1727260065.5657525,
1901 + 0.0
1902 + ],
1903 + [
1904 + 1727260070.563676,
1905 + 0.0
1906 + ],
1907 + [
1908 + 1727260105.6695807,
1909 + 0.0
1910 + ],
1911 + [
1912 + 1727260165.6647935,
1913 + 0.0
1914 + ],
1915 + [
1916 + 1727260212.0559795,
1917 + 0.0
1918 + ]
1919 + ]
1920 + }
1921 + }
1922 + }
1923 +]
src/go/plugin/go.d/modules/init.go
+1
@@ -12,6 +12,7 @@ import (
12 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/bind"
13 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/boinc"
14 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/cassandra"
15 + _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/ceph"
16 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/chrony"
17 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/clickhouse"
18 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/cockroachdb"