Ad Widget

Collapse

Zabbix agent 2 dynamically loadable Go plugin

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • lasseoe
    Junior Member
    • Aug 2008
    • 15

    #1

    Zabbix agent 2 dynamically loadable Go plugin

    Hi,

    I'm fairly sure I saw somewhere that it's either possible or Zabbix is working on it making it possible, to write dynamically loadable plugins in Go, but for some reason I'm unable to find anything at all mentioning this.
    Anyone have anything useful on this topic?

    Thanks,

    /Lasse
  • dimir
    Zabbix developer
    • Apr 2011
    • 1080

    #2
    The documentation on this is almost over. Meanwhile, I can paste here the current version of it:

    A loadable plugin for agent 2 is a stand-alone application that an agent can work with. You don’t need Zabbix sources, you don’t need to compile the agent, all you need is to build the plugin in a desired way.

    Let’s create a loadable plugin that implements one metric called myip that returns the external IP address of the host where the agent is running. It will do so by performing an HTTP request to https://api.ipify.org which returns the IP address of the client connected. Suppose our Go code will be in /usr/local/zabbix/go/plugins/myip directory.

    Open the file main.go:

    Code:
    mkdir -p /usr/local/zabbix/go/plugins/myip
    cd /usr/local/zabbix/go/plugins/myip
    vi main.go
    Add the following code to the file:

    Code:
    // This is the source code of loadable plugin Myip. It implements 1 metric
    // called myip, which returns the expternal IP address of the host where
    // Agent is running.
    
    package main
    
    // Packages we will use. The "plugin-support" ones is a must.
    
    import (
        "fmt"
        "io/ioutil"
        "net/http"
        "git.zabbix.com/ap/plugin-support/plugin/container"
        "git.zabbix.com/ap/plugin-support/plugin"
    )
    
    // Plugin must define structure and embed plugin.Base structure.
    type Plugin struct {
        plugin.Base
    }
    
    var impl Plugin
    
    // Plugin must implement one or several plugin interfaces.
    func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) {
        // You may use one of Critf, Errf, Infof, Warningf, Debugf, Tracef
        // functions for logging.
        p.Infof("received request to handle %s key with %d parameters", key, len(params))
    
        // Fetch response from the specified URL, it should be just the IP address.
        resp, err := http.Get("https://api.ipify.org")
    
        if err != nil {
            panic(err)
        }
    
        defer resp.Body.Close()
    
        body, err := ioutil.ReadAll(resp.Body)
    
        if err != nil {
            panic(err)
        }
    
        return string(body), nil
    }
    
    func init() {
        // Register our metric, specifying the plugin and metric details.
        // 1 - a pointer to plugin implementation
        // 2 - plugin name
        // 3 - metric name (item key)
        // 4 - metric description
        //
        // NB! The metric description must end with period, otherwise the agent won't start!
        plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
    }
    
    // This is the main function. The only important thing
    // here is an impl variable that was defined above.
    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()))
        }
    }
    Again, see the comments in the source code for details.

    Now build the plugin. Some dependencies will be downloaded automatically:

    Code:
    go mod init myip
    GOPROXY=direct go mod tidy
    go build
    The output will be something like:

    Code:
    go: creating new go.mod: module myip
    go: to add module requirements and sums:
    go mod tidy
    go: finding module for package git.zabbix.com/ap/plugin-support/plugin/container
    go: finding module for package git.zabbix.com/ap/plugin-support/plugin
    go: found git.zabbix.com/ap/plugin-support/plugin in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
    go: found git.zabbix.com/ap/plugin-support/plugin/container in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
    An executable myip should be created which is the loadable plugin. Now let’s tell the agent where to find it (ensure the /etc/zabbix_agent2.d/plugins.d path is correct):

    Code:
    echo 'Plugins.Myip.System.Path=/usr/local/zabbix/go/plugins/myip/myip' > /etc/zabbix_agent2.d/plugins.d/myip.conf
    Note the Myip here. This is the name of the plugin we defined in the code when calling plugin.RegisterMetrics() function.

    We’re ready, let’s test the metric:

    Code:
    zabbix_agent2 -t myip
    You should see the external IP address of your host.

    If you face any errors first make sure user zabbix has permissions to access /usr/local/zabbix/go/plugins/myip directory.
    Last edited by dimir; 05-09-2022, 12:32.

    Comment

    • SimonW
      Junior Member
      • Jul 2023
      • 1

      #3
      Thanks for sharing the partial docs. Any progress with it?
      Also, is there some other way to test the plugin? I know that the communication between the agent and the plugin relies on a UNIX socket. So I tried to send some data but I don't know the format. I tried to look through the source code to find out the comms structure, but I don't really understand it.

      Comment

      • dimir
        Zabbix developer
        • Apr 2011
        • 1080

        #4
        So, hopefully the following video will be useful (from 11:18):



        The code:

        https://github.com/dimir/zabbix-exte...2/plugins/myip

        There's no special format of the returned value. So, to put it simple, everything happens in the Export function. You implement what your metric does in it and whatever the function returns will be used as the metric value.

        Let me know if you have more questions.
        Last edited by dimir; 19-09-2023, 16:47.

        Comment

        Working...