fix(go.d/rabbitmq): handle insufficient perms when querying definitions (#19277)
Ilya Mashchenko committed
Dec 23, 2024 at 16:06 UTC
8ff7503a9f920e1740eaffe503903bc95a2f4a12
6 files changed
+48
-7
src/go/plugin/go.d/collector/rabbitmq/collect.go
+23
-2
@@ -6,17 +6,19 @@ import (
6
"encoding/json"
7
"fmt"
8
"net/http"
9
+ "slices"
10
"strings"
11
12
"github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
13
)
14
15
func (c *Collector) collect() (map[string]int64, error) {
15
- if c.clusterName == "" {
16
+ if c.queryClusterMeta {
17
id, name, err := c.getClusterMeta()
18
if err != nil {
19
return nil, err
20
}
21
+ c.queryClusterMeta = false
22
c.clusterId = id
23
c.clusterName = name
24
}
@@ -46,7 +48,26 @@ func (c *Collector) collect() (map[string]int64, error) {
48
}
49
50
func (c *Collector) getClusterMeta() (id string, name string, err error) {
49
- req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathAPIDefinitions)
51
+ req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathAPIWhoami)
52
+ if err != nil {
53
+ return "", "", fmt.Errorf("failed to create whoami request: %w", err)
54
+ }
55
+
56
+ var user apiWhoamiResp
57
+ if err := c.webClient().RequestJSON(req, &user); err != nil {
58
+ return "", "", fmt.Errorf("failed to send whoami request: %w", err)
59
+ }
60
+
61
+ if user.Name == "" {
62
+ return "", "", fmt.Errorf("unexpected response: whoami: user name n is empty")
63
+ }
64
+
65
+ if !slices.Contains(user.Tags, "administrator") {
66
+ c.Warningf("user %s lacks 'administrator' tag: cluster ID and name cannot be collected.", user.Name)
67
+ return "", "", nil
68
+ }
69
+
70
+ req, err = web.NewHTTPRequestWithPath(c.RequestConfig, urlPathAPIDefinitions)
71
if err != nil {
72
return "", "", fmt.Errorf("failed to create definitions request: %w", err)
73
}
src/go/plugin/go.d/collector/rabbitmq/collect_nodes.go
+1
@@ -4,6 +4,7 @@ package rabbitmq
4
5
import (
6
"fmt"
7
+
8
"github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/metrix"
9
10
"github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
src/go/plugin/go.d/collector/rabbitmq/collector.go
+7
-5
@@ -42,8 +42,9 @@ func New() *Collector {
42
CollectQueues: false,
43
},
44
45
- charts: &module.Charts{},
46
- cache: newCache(),
45
+ charts: &module.Charts{},
46
+ cache: newCache(),
47
+ queryClusterMeta: true,
48
}
49
}
50
@@ -62,9 +63,10 @@ type Collector struct {
63
64
httpClient *http.Client
65
65
- clusterName string
66
- clusterId string
67
- cache *cache
66
+ queryClusterMeta bool
67
+ clusterName string
68
+ clusterId string
69
+ cache *cache
70
}
71
72
func (c *Collector) Configuration() any {
src/go/plugin/go.d/collector/rabbitmq/collector_test.go
+4
@@ -20,6 +20,7 @@ var (
20
dataConfigJSON, _ = os.ReadFile("testdata/config.json")
21
dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
22
23
+ dataClusterWhoami, _ = os.ReadFile("testdata/v4.0.3/cluster/whoami.json")
24
dataClusterDefinitions, _ = os.ReadFile("testdata/v4.0.3/cluster/definitions.json")
25
dataClusterOverview, _ = os.ReadFile("testdata/v4.0.3/cluster/overview.json")
26
dataClusterNodes, _ = os.ReadFile("testdata/v4.0.3/cluster/nodes.json")
@@ -31,6 +32,7 @@ func Test_testDataIsValid(t *testing.T) {
32
for name, data := range map[string][]byte{
33
"dataConfigJSON": dataConfigJSON,
34
"dataConfigYAML": dataConfigYAML,
35
+ "dataClusterWhoami": dataClusterWhoami,
36
"dataClusterDefinitions": dataClusterDefinitions,
37
"dataClusterOverview": dataClusterOverview,
38
"dataClusterNodes": dataClusterNodes,
@@ -379,6 +381,8 @@ func caseClusterOk() (*Collector, func()) {
381
http.HandlerFunc(
382
func(w http.ResponseWriter, r *http.Request) {
383
switch r.URL.Path {
384
+ case urlPathAPIWhoami:
385
+ _, _ = w.Write(dataClusterWhoami)
386
case urlPathAPIDefinitions:
387
_, _ = w.Write(dataClusterDefinitions)
388
case urlPathAPIOverview:
src/go/plugin/go.d/collector/rabbitmq/restapi.go
+6
@@ -3,6 +3,7 @@
3
package rabbitmq
4
5
const (
6
+ urlPathAPIWhoami = "/api/whoami"
7
urlPathAPIDefinitions = "/api/definitions"
8
urlPathAPIOverview = "/api/overview"
9
urlPathAPINodes = "/api/nodes"
@@ -10,6 +11,11 @@ const (
11
urlPathAPIQueues = "/api/queues"
12
)
13
14
+type apiWhoamiResp struct {
15
+ Name string `json:"name"`
16
+ Tags []string `json:"tags"`
17
+}
18
+
19
type apiDefinitionsResp struct {
20
RabbitmqVersion string `json:"rabbitmq_version"`
21
GlobalParams []struct {
src/go/plugin/go.d/collector/rabbitmq/testdata/v4.0.3/cluster/whoami.json
new
+7
@@ -0,0 +1,7 @@
1
+{
2
+ "name": "guest",
3
+ "tags": [
4
+ "administrator"
5
+ ],
6
+ "is_internal_user": true
7
+}