From 37e6813d6f3bff33a3857c1ff89e246bd9d8668b Mon Sep 17 00:00:00 2001 From: imbytecat Date: Fri, 23 Aug 2024 10:37:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=20zabbix=20agent=20=E4=BD=9C?= =?UTF-8?q?=E4=B8=BA=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.yaml | 1 + config/integration.go | 3 +- integration/zabbixagent/plugin/handler.go | 68 ++++++++++++++++++ integration/zabbixagent/plugin/plugin.go | 86 ++++++++++++++++++----- 4 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 integration/zabbixagent/plugin/handler.go diff --git a/config.yaml b/config.yaml index 9fed5b5..2671bcb 100644 --- a/config.yaml +++ b/config.yaml @@ -9,3 +9,4 @@ integrations: zabbix_agent: plugin: name: "Onvif" + version: "1.0.0" diff --git a/config/integration.go b/config/integration.go index 6983a63..47d605a 100644 --- a/config/integration.go +++ b/config/integration.go @@ -5,5 +5,6 @@ type IntegrationConfig struct { } type PluginConfig struct { - Name string `mapstructure:"name"` + Name string `mapstructure:"name"` + Version string `mapstructure:"version"` } diff --git a/integration/zabbixagent/plugin/handler.go b/integration/zabbixagent/plugin/handler.go new file mode 100644 index 0000000..9c56121 --- /dev/null +++ b/integration/zabbixagent/plugin/handler.go @@ -0,0 +1,68 @@ +package plugin + +import ( + "context" + "fmt" + "golang.zabbix.com/sdk/errs" + "io" + "net/http" + "onvif-agent/config" + "strings" +) + +// HandlerFunc describes the signature all metric handler functions must have. +type HandlerFunc func( + ctx context.Context, + metricParams map[string]string, + extraParams ...string, +) (any, error) + +// Handler hold client and syscall implementation for request functions. +type Handler struct { + client *http.Client +} + +func (h *Handler) GetPluginVersion(_ context.Context, _ map[string]string, _ ...string) (any, error) { + return config.Conf.Integrations.ZabbixAgent.Plugin.Version, nil +} + +func (h *Handler) HTTPClient(ctx context.Context, params map[string]string, _ ...string) (any, error) { + method := params["method"] + if method == "" { + method = http.MethodGet + } + + url := params["url"] + if !strings.HasPrefix(url, "http") { + url = fmt.Sprintf("http://localhost:%d/%s", config.Conf.Server.Port, url) + } + + body := params["body"] + + //req, err := http.NewRequestWithContext(ctx, method, "https://api.imbytecat.com/ip", http.NoBody) + req, err := http.NewRequestWithContext(ctx, method, "https://api.imbytecat.com/ip", strings.NewReader(body)) + if err != nil { + return nil, errs.Wrapf(err, "failed to create request") + } + + resp, err := h.client.Do(req) + if err != nil { + return nil, errs.Wrapf(err, "failed to send the request") + } + + defer resp.Body.Close() + + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, errs.Wrapf(err, "failed to read the response") + } + + return string(data), nil +} + +// NewHandler creates a new handler with initialized clients for system and tcp calls. +func NewHandler() *Handler { + return &Handler{ + client: http.DefaultClient, + } +} diff --git a/integration/zabbixagent/plugin/plugin.go b/integration/zabbixagent/plugin/plugin.go index 4779fb0..fb3b234 100644 --- a/integration/zabbixagent/plugin/plugin.go +++ b/integration/zabbixagent/plugin/plugin.go @@ -1,19 +1,28 @@ package plugin import ( + "context" "golang.zabbix.com/sdk/errs" "golang.zabbix.com/sdk/metric" "golang.zabbix.com/sdk/plugin" "golang.zabbix.com/sdk/plugin/container" + "golang.zabbix.com/sdk/zbxerr" "onvif-agent/config" + "time" ) -var ( - PluginName = config.Conf.Integrations.ZabbixAgent.Plugin.Name -) +var Name = config.Conf.Integrations.ZabbixAgent.Plugin.Name + +type metricKey string + +type metricBinding struct { + metric *metric.Metric + handler HandlerFunc +} type zabbixAgentPlugin struct { plugin.Base + metrics map[metricKey]*metricBinding } // Launch launches the plugin. Blocks until plugin execution has finished. @@ -25,7 +34,7 @@ func Launch() error { return err } - h, err := container.NewHandler(PluginName) + h, err := container.NewHandler(Name) if err != nil { return errs.Wrap(err, "failed to create new handler") } @@ -40,20 +49,65 @@ func Launch() error { return nil } -func (p *zabbixAgentPlugin) registerMetrics() error { - metricSet := metric.MetricSet{ - "onvif.client": metric.New( - "ONVIF client", - []*metric.Param{ - metric.NewParam("method", "HTTP method"), - metric.NewParam("url", "URL"), - metric.NewParam("data", "Request data"), - }, - false, - ), +// Export collects all the metrics. +func (p *zabbixAgentPlugin) Export(key string, rawParams []string, _ plugin.ContextProvider) (any, error) { + b, ok := p.metrics[metricKey(key)] + if !ok { + return nil, errs.Wrapf(zbxerr.ErrorUnsupportedMetric, "unknown metric %q", key) } - err := plugin.RegisterMetrics(p, PluginName, metricSet.List()...) + metricParams, extraParams, _, err := b.metric.EvalParams(rawParams, nil) + if err != nil { + return nil, errs.Wrap(err, "failed to evaluate metric parameters") + } + + ctx, cancel := context.WithTimeout( + context.Background(), + 30*time.Second, // TODO: make configurable + ) + defer cancel() + + res, err := b.handler(ctx, metricParams, extraParams...) + if err != nil { + return nil, errs.Wrap(err, "failed to execute handler") + } + + return res, nil +} + +func (p *zabbixAgentPlugin) registerMetrics() error { + h := NewHandler() + + p.metrics = map[metricKey]*metricBinding{ + "onvif.version": { + metric: metric.New( + "ONVIF plugin version", + nil, + false, + ), + handler: h.GetPluginVersion, + }, + "onvif.client": { + metric: metric.New( + "ONVIF client", + []*metric.Param{ + metric.NewParam("method", "HTTP request method."), + metric.NewParam("url", "HTTP request URL."), + metric.NewParam("body", "HTTP request body."), + }, + false, + ), + handler: h.HTTPClient, + }, + } + + metricSet := metric.MetricSet{} + + for k, m := range p.metrics { + metricSet[string(k)] = m.metric + } + + err := plugin.RegisterMetrics(p, Name, metricSet.List()...) if err != nil { return errs.Wrap(err, "failed to register metrics") }