master
go 156 lines 3.73 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package powerstore
4
5 import (
6 "context"
7 _ "embed"
8 "errors"
9 "fmt"
10 "time"
11
12 "github.com/netdata/netdata/go/plugins/pkg/confopt"
13 "github.com/netdata/netdata/go/plugins/pkg/matcher"
14 "github.com/netdata/netdata/go/plugins/pkg/metrix"
15 "github.com/netdata/netdata/go/plugins/pkg/web"
16 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
17 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/powerstore/client"
18 )
19
20 //go:embed "config_schema.json"
21 var configSchema string
22
23 //go:embed "charts.yaml"
24 var chartTemplateYAML string
25
26 func init() {
27 collectorapi.Register("powerstore", collectorapi.Creator{
28 JobConfigSchema: configSchema,
29 Defaults: collectorapi.Defaults{
30 UpdateEvery: 30,
31 },
32 CreateV2: func() collectorapi.CollectorV2 { return New() },
33 Config: func() any { return &Config{} },
34 })
35 }
36
37 const maxConcurrentAPIRequests = 10
38
39 func New() *Collector {
40 store := metrix.NewCollectorStore()
41 mx := newCollectorMetrics(store)
42
43 return &Collector{
44 Config: Config{
45 HTTPConfig: web.HTTPConfig{
46 RequestConfig: web.RequestConfig{
47 URL: "https://127.0.0.1",
48 },
49 ClientConfig: web.ClientConfig{
50 Timeout: confopt.Duration(30 * time.Second),
51 },
52 },
53 },
54 store: store,
55 mx: mx,
56 sem: make(chan struct{}, maxConcurrentAPIRequests),
57 }
58 }
59
60 type Config struct {
61 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
62 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
63 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
64 web.HTTPConfig `yaml:",inline" json:""`
65 VolumeSelector string `yaml:"volume_selector,omitempty" json:"volume_selector"`
66 }
67
68 type (
69 Collector struct {
70 collectorapi.Base
71 Config `yaml:",inline" json:""`
72
73 store metrix.CollectorStore
74 mx *collectorMetrics
75
76 client *client.Client
77
78 discovered discovered
79 lastDiscoveryOK bool
80 runs int
81
82 volMatcher matcher.Matcher
83 sem chan struct{} // limits concurrent API calls
84 }
85 discovered struct {
86 clusters []client.Cluster
87 appliances map[string]client.Appliance
88 volumes map[string]client.Volume
89 nodes map[string]client.Node
90 fcPorts map[string]client.FcPort
91 ethPorts map[string]client.EthPort
92 fileSystems map[string]client.FileSystem
93 nasServers map[string]client.NAS
94 drives map[string]client.Hardware
95 hardware []client.Hardware
96 }
97 )
98
99 func (c *Collector) Configuration() any {
100 return c.Config
101 }
102
103 func (c *Collector) Init(context.Context) error {
104 if c.Username == "" || c.Password == "" {
105 return errors.New("config: username and password aren't set")
106 }
107
108 cli, err := client.New(c.ClientConfig, c.RequestConfig)
109 if err != nil {
110 return fmt.Errorf("error creating PowerStore client: %v", err)
111 }
112 c.client = cli
113
114 if c.VolumeSelector != "" {
115 m, err := matcher.NewSimplePatternsMatcher(c.VolumeSelector)
116 if err != nil {
117 return fmt.Errorf("error creating volume selector: %v", err)
118 }
119 c.volMatcher = m
120 }
121
122 c.Debugf("using URL %s", c.URL)
123 c.Debugf("using timeout: %s", c.Timeout)
124
125 return nil
126 }
127
128 func (c *Collector) volumeMatches(name string) bool {
129 if c.volMatcher == nil {
130 return true
131 }
132 return c.volMatcher.MatchString(name)
133 }
134
135 func (c *Collector) Check(context.Context) error {
136 if err := c.client.Login(); err != nil {
137 return err
138 }
139 // Verify API access by running discovery (no metrics written).
140 return c.discovery()
141 }
142
143 func (c *Collector) Collect(context.Context) error {
144 return c.collect()
145 }
146
147 func (c *Collector) MetricStore() metrix.CollectorStore { return c.store }
148
149 func (c *Collector) ChartTemplateYAML() string { return chartTemplateYAML }
150
151 func (c *Collector) Cleanup(context.Context) {
152 if c.client == nil {
153 return
154 }
155 c.client.Logout()
156 }