创建插件(教程)

这是为 Zabbix agent 2 创建一个简单可加载插件的分步教程。

您可以随意使用我们的示例仓库作为创建您自己插件的模板或指南。

您将创建的内容

在本教程中,您将添加一个新的可加载插件 MyIP。该插件将实现一个名为 myip 的指标, 该指标返回运行 Zabbix agent2 的主机的外部 IP 地址。

第一部分: 用go语言写一个插件

在本节中,您将学习如何编写向 Zabbix Agent 2 添加新指标的插件 1.在/usr/local/zabbix/go/plugins/目录新建一个myip 目录。 2. 在 myip 目录中创建文件 main.go 并定义您的 Go 包的名称。 /usr/local/zabbix/go/plugins/myip/main.go

package main

保持文件打开以按照后续步骤添加更多行。

  1. 指定要导入的包

这些是插件所依赖的包 /usr/local/zabbix/go/plugins/myip/main.go

package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
  1. 定义插件结构。

嵌入plugin.Base结构以访问标准插件功能。 /usr/local/zabbix/go/plugins/myip/main.go

package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
  1. 实现插件接口 Export。 Export 接口执行轮询并返回一个值。 /usr/local/zabbix/go/plugins/myip/main.go
package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error)
  1. 添加日志记录。日志消息将出现在 Zabbix Aget 2 日志中。 您可以使用插件可用的日志记录功能之一:Critf()Errf()Infof()Warningf()Debugf()Tracef()/usr/local/zabbix/go/plugins/myip/main.go
package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
       }
  1. 实现核心插件逻辑。 该逻辑从指定的 URL 获取响应并读取它,然后返回 IP 地址作为响应并关闭请求。如果在执行 GET 请求或读取响应时出现错误,则返回错误。

/usr/local/zabbix/go/plugins/myip/main.go

package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
  1. 注册metric。 Zabbix agent 2启动时会初始化运行init()函数,该函数会调用plugin.RegisterMetrics(structure, plugin name, metric name, description)方法获取插件数据, plugin.RegisterMetrics方法参数说明:
  • structure - 指向插件实现的指针;授予对插件结构的访问权限,包括可用插件接口列表(例如,&impl)。
  • name - 插件名称;必须是唯一的(例如,“Myip”)。
  • metric name - metric 名称(例如,“myip”)。这是用于从插件收集数据的项目键。
  • description - metric 描述;必须以大写字母开头并以句点结尾(例如,“返回agent 正在运行的主机的外部 IP 地址。”)。

要注册多个指标,请为每个指标重复参数 metric namedescription。例如​​:plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")

*/usr/local/zabbix/go/plugins/myip/main.go**

package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
       func init() {
           plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
       }
  1. 定义 main() 函数,该函数将创建一个新的插件处理程序实例,将其分配给插件用于日志记录,然后执行插件处理程序。 ::: 注意事项 定义 main() 函数是必须的。 ::: /usr/local/zabbix/go/plugins/myip/main.go
package main
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       type Plugin struct {
           plugin.Base
       }
              
       var impl Plugin
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
       func init() {
           plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
       }
       func main() {
           h, err := container.NewHandler(impl.Name())
           if err != nil {
               panic(fmt.Sprintf("failed to create plugin handler %s", err.Error()))
           }
           impl.Logger = &h
              
           err = h.Execute()
           if err != nil {
               panic(fmt.Sprintf("failed to execute plugin handler %s", err.Error()))
           }
       }

第 2 部分:构建插件

在本节中,您将学习如何编译插件。

  1. 要创建用于依赖项处理的 Go 文件并自动下载依赖项,请从 CLI 执行此 bash 脚本。
go mod init myip
       GOPROXY=direct go get git.zabbix.com/ap/plugin-support/plugin@branchname
       go mod tidy
       go build

确保指定正确的分支名称,即用以下之一替换 branchname(参见第 2 行):

  • release/* - 表示稳定发布分支,其中“*”表示发布版本(即 7.0
  • master - 表示 master 分支
  • <commit hash> - 表示特定提交版本(使用特定提交哈希)

输出应类似于以下内容:

go:创建新的 go.mod:模块 myip
       go:添加模块要求和总和:
       go mod tidy
       go:查找软件包 git.zabbix.com/ap/plugin-support/plugin/container 的模块
       go:查找软件包的模块git.zabbix.com/ap/plugin-support/plugin
       go: 在 git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0 中找到 git.zabbix.com/ap/plugin-support/plugin
       go: 在 git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0 中找到 git.zabbix.com/ap/plugin-support/plugin/container
  1. 为可加载插件创建可执行文件 myip

  2. 在 Zabbix agent2 配置文件的 Plugins.Myip.System.Path 参数中指定插件配置文件的路径。

配置参数名称中的插件名称(本教程中为 Myip)必须与 plugin.RegisterMetrics() 函数中定义的插件名称匹配。

echo 'Plugins.Myip.System.Path=/usr/local/zabbix/go/plugins/myip/myip' > /etc/zabbix_agent2.d/plugins.d/myip.conf
  1. 测试指标:
zabbix_agent2 -t myip

响应应包含主机的外部 IP 地址。

如果出现错误,请检查用户 zabbix 是否有权访问 /usr/local/zabbix/go/plugins/myip 目录。