feat: 初步集成 zabbix agent
This commit is contained in:
parent
e148d8aeda
commit
dc53b3aaf8
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Wukong: Simplified Management of ONVIF IP Devices
|
||||
|
||||
Wukong is a robust implementation of the ONVIF protocol designed for the efficient management of ONVIF-compliant IP devices, including cameras. This project aims to provide a user-friendly and streamlined solution for the convenient management of IP cameras and other devices that adhere to the ONVIF standard.
|
||||
|
||||
With Wukong, users can easily configure, monitor, and control their ONVIF devices, enhancing the overall experience of managing surveillance systems and ensuring seamless integration within various environments.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Zabbix agent 2 version 6.0.0 or newer
|
||||
- Go programming language version 1.20 or newer (required only for building the plugin from the source)
|
||||
|
||||
## Installation
|
||||
|
||||
The plugin can be compiled using `go build`.
|
||||
|
@ -4,3 +4,8 @@ server:
|
||||
|
||||
app:
|
||||
url: "http://localhost:8080"
|
||||
|
||||
integrations:
|
||||
zabbix_agent:
|
||||
plugin:
|
||||
name: "Onvif"
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
type config struct {
|
||||
Server serverConfig `mapstructure:"server"`
|
||||
App appConfig `mapstructure:"app"`
|
||||
Integrations integrationConfig `mapstructure:"integrations"`
|
||||
}
|
||||
|
||||
type serverConfig struct {
|
||||
@ -21,6 +22,10 @@ type appConfig struct {
|
||||
URL string `mapstructure:"url"`
|
||||
}
|
||||
|
||||
type integrationConfig struct {
|
||||
ZabbixAgent IntegrationConfig `mapstructure:"zabbix_agent"`
|
||||
}
|
||||
|
||||
var Conf config
|
||||
|
||||
func LoadConfig() error {
|
||||
|
9
config/integration.go
Normal file
9
config/integration.go
Normal file
@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
type IntegrationConfig struct {
|
||||
Plugin PluginConfig `mapstructure:"plugin"`
|
||||
}
|
||||
|
||||
type PluginConfig struct {
|
||||
Name string `mapstructure:"name"`
|
||||
}
|
5
go.mod
5
go.mod
@ -6,9 +6,11 @@ require (
|
||||
github.com/IOTechSystems/onvif v1.1.2
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/spf13/viper v1.19.0
|
||||
golang.zabbix.com/sdk v1.2.2-0.20240801124644-68a74164363d
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/beevik/etree v1.4.0 // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
@ -47,9 +49,12 @@ require (
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.26.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
14
go.sum
14
go.sum
@ -1,5 +1,7 @@
|
||||
github.com/IOTechSystems/onvif v1.1.2 h1:czmvGY+0oGHwsczDqh5aRatp/PIil8vYHJckljLp4iI=
|
||||
github.com/IOTechSystems/onvif v1.1.2/go.mod h1:4pizduM+kbnuiJpd9xBgVX5/hsZPcH9bj/iZUeCvYy8=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/beevik/etree v1.4.0 h1:oz1UedHRepuY3p4N5OjE0nK1WLCqtzHf25bxplKOHLs=
|
||||
github.com/beevik/etree v1.4.0/go.mod h1:cyWiXwGoasx60gHvtnEh5x8+uIjUVnjWqBvEnhnqKDA=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
@ -38,8 +40,8 @@ github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBEx
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
@ -116,14 +118,22 @@ golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.zabbix.com/sdk v1.2.2-0.20240801124644-68a74164363d h1:ApDsjHJ3/hQ8U/QBww/9bYoeAAm3fx5XFc/YBJz/a1c=
|
||||
golang.zabbix.com/sdk v1.2.2-0.20240801124644-68a74164363d/go.mod h1:KFfJAnUsBIfLemmPVz7TJPliJAwYUSuj4v3n5W1qrCQ=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
63
integration/zabbixagent/main.go
Normal file
63
integration/zabbixagent/main.go
Normal file
@ -0,0 +1,63 @@
|
||||
package zabbixagent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"onvif-agent/config"
|
||||
"onvif-agent/integration/zabbixagent/plugin"
|
||||
"os"
|
||||
|
||||
"golang.zabbix.com/sdk/plugin/flag"
|
||||
"golang.zabbix.com/sdk/zbxerr"
|
||||
)
|
||||
|
||||
const copyrightMessage = //
|
||||
`Copyright 2001-%d imbytecat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
`
|
||||
const (
|
||||
pluginVersionMajor = 1
|
||||
pluginVersionMinor = 0
|
||||
pluginVersionPatch = 0
|
||||
pluginVersionRC = "alpha1"
|
||||
pluginLicenseYear = 2024
|
||||
)
|
||||
|
||||
func Run() error {
|
||||
err := flag.HandleFlags(
|
||||
config.Conf.Integrations.ZabbixAgent.Plugin.Name,
|
||||
os.Args[0],
|
||||
fmt.Sprintf(copyrightMessage, pluginLicenseYear),
|
||||
pluginVersionRC,
|
||||
pluginVersionMajor,
|
||||
pluginVersionMinor,
|
||||
pluginVersionPatch,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, zbxerr.ErrorOSExitZero) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
err = plugin.Launch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
43
integration/zabbixagent/plugin/handler/handler.go
Normal file
43
integration/zabbixagent/plugin/handler/handler.go
Normal file
@ -0,0 +1,43 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 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
|
||||
sysCalls systemCalls
|
||||
}
|
||||
|
||||
type systemCalls interface {
|
||||
environ() []string
|
||||
lookupEnv(key string) (string, bool)
|
||||
}
|
||||
|
||||
type osWrapper struct{}
|
||||
|
||||
// New creates a new handler with initialized clients for system and tcp calls.
|
||||
func New() *Handler {
|
||||
return &Handler{
|
||||
client: http.DefaultClient,
|
||||
sysCalls: osWrapper{},
|
||||
}
|
||||
}
|
||||
|
||||
func (osWrapper) environ() []string {
|
||||
return os.Environ()
|
||||
}
|
||||
|
||||
func (osWrapper) lookupEnv(key string) (string, bool) {
|
||||
return os.LookupEnv(key)
|
||||
}
|
102
integration/zabbixagent/plugin/plguin.go
Normal file
102
integration/zabbixagent/plugin/plguin.go
Normal file
@ -0,0 +1,102 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"golang.zabbix.com/sdk/errs"
|
||||
"golang.zabbix.com/sdk/metric"
|
||||
"golang.zabbix.com/sdk/plugin"
|
||||
"golang.zabbix.com/sdk/plugin/container"
|
||||
"onvif-agent/config"
|
||||
"onvif-agent/integration/zabbixagent/plugin/handler"
|
||||
)
|
||||
|
||||
var (
|
||||
Name = config.Conf.Integrations.ZabbixAgent.Plugin.Name
|
||||
)
|
||||
|
||||
type onvifMetricKey string
|
||||
|
||||
type onvifMetric struct {
|
||||
metric *metric.Metric
|
||||
handler handler.HandlerFunc
|
||||
}
|
||||
|
||||
type onvifPlugin struct {
|
||||
plugin.Base
|
||||
metrics map[onvifMetricKey]*onvifMetric
|
||||
}
|
||||
|
||||
// Launch launches the plugin. Blocks until plugin execution has finished.
|
||||
func Launch() error {
|
||||
p := &onvifPlugin{}
|
||||
|
||||
err := p.registerMetrics()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h, err := container.NewHandler(Name)
|
||||
if err != nil {
|
||||
return errs.Wrap(err, "failed to create new handler")
|
||||
}
|
||||
|
||||
p.Logger = &h
|
||||
|
||||
err = h.Execute()
|
||||
if err != nil {
|
||||
return errs.Wrap(err, "failed to execute plugin handler")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start starts the example plugin. Is required for plugin to match runner interface.
|
||||
func (p *onvifPlugin) Start() {
|
||||
p.Logger.Infof("Start called")
|
||||
}
|
||||
|
||||
// Stop stops the example plugin. Is required for plugin to match runner interface.
|
||||
func (p *onvifPlugin) Stop() {
|
||||
p.Logger.Infof("Stop called")
|
||||
}
|
||||
|
||||
func (p *onvifPlugin) registerMetrics() error {
|
||||
//h := handler.New()
|
||||
|
||||
p.metrics = map[onvifMetricKey]*onvifMetric{
|
||||
//myIPMetric: {
|
||||
// metric: metric.New(
|
||||
// "Returns the availability groups.",
|
||||
// params.Params,
|
||||
// false,
|
||||
// ),
|
||||
// handler: handler.WithJSONResponse(
|
||||
// handler.WithCredentialValidation(
|
||||
// h.MyIP,
|
||||
// ),
|
||||
// ),
|
||||
//},
|
||||
//goEnvMetric: {
|
||||
// metric: metric.New(
|
||||
// "Returns the result rows of a custom query.",
|
||||
// params.Params,
|
||||
// true,
|
||||
// ),
|
||||
// handler: handler.WithJSONResponse(
|
||||
// handler.WithCredentialValidation(handler.GoEnvironment),
|
||||
// ),
|
||||
//},
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
22
main.go
22
main.go
@ -5,6 +5,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"onvif-agent/config"
|
||||
"onvif-agent/integration/zabbixagent"
|
||||
"onvif-agent/router"
|
||||
)
|
||||
|
||||
@ -12,17 +13,30 @@ func main() {
|
||||
if err := config.LoadConfig(); err != nil {
|
||||
log.Fatalf("Error loading config: %v", err)
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", config.Conf.Server.Host, config.Conf.Server.Port)
|
||||
|
||||
/**
|
||||
* Web server
|
||||
*/
|
||||
go func() {
|
||||
r := gin.Default()
|
||||
|
||||
router.SetupRoutes(r)
|
||||
|
||||
go func() {
|
||||
err := r.Run(addr)
|
||||
if err != nil {
|
||||
addr := fmt.Sprintf("%s:%d", config.Conf.Server.Host, config.Conf.Server.Port)
|
||||
if err := r.Run(addr); err != nil {
|
||||
fmt.Println("Failed to start server:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
/**
|
||||
* Zabbix agent
|
||||
*/
|
||||
go func() {
|
||||
err := zabbixagent.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to start Zabbix agent integration:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
select {}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"onvif-agent/service/onvif"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var conns = make(map[string]*onvif.Connection)
|
||||
@ -22,13 +21,7 @@ func CreateConnection(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 规范化连接地址
|
||||
xaddr := req.Xaddr
|
||||
if !strings.Contains(xaddr, ":") {
|
||||
xaddr += ":80"
|
||||
}
|
||||
|
||||
conn, err := onvif.NewConnection(xaddr, req.Username, req.Password)
|
||||
conn, err := onvif.New(req.Xaddr, req.Username, req.Password)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"message": err.Error(),
|
||||
|
@ -2,13 +2,19 @@ package onvif
|
||||
|
||||
import (
|
||||
"github.com/IOTechSystems/onvif"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Connection struct {
|
||||
Device *onvif.Device `json:"device"`
|
||||
}
|
||||
|
||||
func NewConnection(xaddr string, username string, password string) (*Connection, error) {
|
||||
func New(xaddr string, username string, password string) (*Connection, error) {
|
||||
// 规范化连接地址
|
||||
if !strings.Contains(xaddr, ":") {
|
||||
xaddr += ":80"
|
||||
}
|
||||
|
||||
dev, err := onvif.NewDevice(onvif.DeviceParams{
|
||||
Xaddr: xaddr,
|
||||
Username: username,
|
||||
|
Loading…
x
Reference in New Issue
Block a user