Write your blackbird plugin # 002

This time, let's write the Blackbird plugin. In the second installment, we will introduce how to write a really simple plugin! The detailed explanation of each method is left to the third bullet, so it may be covered with the first bullet, the second bullet, and the third bullet, respectively. Please watch over with lukewarm eyes.

outline

As a rough procedure,

  1. Get the base class of plugin
  2. Create a concrete class
  3. Implementation of method executed on Thread generated from Main process
  4. Format of the item to put in the Queue
  5. Config Validation settings

It is like this.

  1. Get the base class of plugin

The base class is contained in the blackbird body,

pip install blackbird

You can easily get it at.

  1. Create a concrete class

Well, on the plug-in side you create


# blackbird.plugins.import base module
import blackbird.plugins.base


#Inherit JobBase abstract class
class ConcreteJob(blackbird.plugins.base.JobBase):
    pass

If you specify, the creation of the concrete class is completed. As a point to note, ** the class name is fixed in ConcreteJob **, so if you use a different class name, it will not work.

  1. Implementation of method executed on Thread generated from Main process

When putting an item into the Queue, the Main process expects to be able to call ** ConcreteJob.build_items **. Code-wise


import YOUR_MODULE

YOUR_MODULE.ConcreteJob.build_items()

If you can't do that, the item won't actually get stuck in the Queue. So ** be sure to implement the method with the name build_items **. At that time, since the enqueue method is implemented on the base class side, either execute the enqueue method of the parent class in build_items or If you want to implement the enqueue method on the concrete class side, either override it or implement the _ \ enqueue method. To summarize the story so far,


import blackbird.plugins.base


class ConcreteJob(blackbird.plugins.base.JobBase):

    def build_items(self):
        #Item names to be put in Queue and Queue will be described later.
        items = {
            'HOGEHOGE': 'FUGAFUGA'
        }

I wonder if it will look like this.

  1. Format of the item to put in the Queue

So, if you match the format of the Queue item that you actually put in, the implementation is almost complete as a function. The items to put in the Queue are very simple and use the Python dict format. In particular


ITEM = {
    'key': 'ANYTHING_OK',
    'value': '1.0000',
    'host': 'HOSTNAME_ON_ZABBIX_SERVER',
    'clock': datetime.datetime()
}

It looks like this.

key

key is a key on zabbix template, for example, if you are familiar with it, you can imagine something like ʻagent.ping`. So, if you specify a key name that is too abstract, there is a high possibility that it will be overwhelmed, so it may be a bit redundant or long, but I wonder if something that is easy to identify is good.

value

This value is the actual value that sender sends to the destination (only for zabbix server now). I don't think there is much need to explain this, but 1 or 0 flag-type values are fine, and It doesn't matter if it's a decimal point like 1.234567 or a character string. However, considering various integrations, I think it is safe to use floating point numbers.

host

Host is the name of Host on Zabbix Server because it is assumed that zabbix server is the destination now. This will specify which Host you want to send the value to. However, I think it is difficult to create a mechanism to inject from the outside, so with Validation of config described later The value of hostname specified in config in cooperation will be entered here.

clock

clock is a datetime.datetime instance of Python. This was also troublesome to integrate on the Plugin side one by one, so on the base class side, I set the time when the instance was created to be entered as the value of clock.

4.5. Actually, you don't have to integrate the Item yourself www

I wrote it in 4., so I think it's a good idea, but Item defines a ʻItemBase` class that returns a dict object. So

Does not need to be implemented on the plugin developer side.

About the blackbird.plugins.base.ItemBase class

As I mentioned a little earlier, this class is an abstract class that returns a dict type object. I haven't done anything particularly difficult, I call _generate with __init __ and generate a dict in it. When I write _return like _, I actually make a getter method named data `` @ propertyand return dict withConcreteItem.data`.

Did you write too much in detail ..... The story that is too detailed in this area is kwsk in the next third bullet !!

To summarize the story so far,

import blackbird.plugins.base

class ConcreteJob(blackbird.plugins.base.JobBase):

    def build_items(self):
        item=ConcreteItem(
           key='isPublished',
           value=1,
           #self.config will be described later together with Validation.
           host=self.config.get('hostname')
        )
        self.enqueue(
            item=item
        )

class ConcreteItem(blackbird.plugins.base.ItemBase):

    def __init__(self, key, value, host):
        super(ConcreteItem, self).__init__(key, value, host)

        self.__data = dict()
        self._generate()

    @property
    def data(self):
        return self.__data

    def _generate(self):
        """
For example, if you want to add a specific prefix to the key, like this
        self.__data['key'] = 'YOUR_PREFIX.' + self.key
If you write here
        """
        self.__data['key'] = self.key
        self.__data['value'] = self.value
        self.__data['host'] = self.host
        self.__data['clock'] = self.clock

You can create a ConcreteItem like this, put it in a Queue, and send it to zabbix \ _sender plugin.

  1. Config Validation settings

Validation is actually okay without setting it. If you write it in the config file, the key and value will be in blackbird.plugins.base.JobBase.config as it is It is stored as a dict type object. For example

[MY_BLACKBIRD_PLUGIN]
hostname = hogehoge.com
module = MODULE_NAME

If you write, you can access the value in config by just doing self.config ['hostname']. However, you want a required value, so it's Validation. The Validation object is also integrated on the base class side, and it feels like writing the Validation settings using a character string.

When I actually write it,

class Validator(blackbird.plugins.base.ValidatorBase):
    def __init__(self):
        self.__spec = None

    @property
    def spec(self):
        self.__spec = (
            "[0]".format(__name__),
            "required_parameter = string()",
            "not_required_paramter = string(default='DEFAULT_STRING')"
        )
        return self.__spec

It is like this. ** The class name is fixed to Validator **. I packed a little bit and it got confusing, but I will leave the details to the third bullet, but only the points roughly.

Summary

If you implement the contents so far as it is, the plugin is actually completed.

#Import module containing abstract class for plugin from blackbird
import blackbird.plugins.base

#Create a ConcreteJob that inherits the JobBase abstract class
#Class name is fixed to ConcreteJob
class ConcreteJob(blackbird.plugins.base.JobBase):

# build_Since the items method is called from the Main process, build_items are fixed names
    def build_items(self):
        item = self.generate_items()
        self.enqueue(
            item=item
        )

    def generate_items(self)
        return ConcreteItem(
           key='isPublished',
           value=1,
           host=self.config.get('hostname')
        )

class ConcreteItem(blackbird.plugins.base.ItemBase):

    def __init__(self, key, value, host):
        super(ConcreteItem, self).__init__(key, value, host)

        self.__data = dict()
        self._generate()

    @property
    def data(self):
        return self.__data

    def _generate(self):
        self.__data['key'] = self.key
        self.__data['value'] = self.value
        self.__data['host'] = self.host
        self.__data['clock'] = self.clock

class Validator(blackbird.plugins.base.ValidatorBase):
    def __init__(self):
        self.__spec = None

    @property
    def spec(self):
        self.__spec = (
            "[0]".format(__name__),
            "required_parameter = string()",
            "not_required_paramter = string(default='DEFAULT_STRING')"
        )
        return self.__spec


if __name__ == '__main__':
    OPTIONS = {
        'required_parameter': 'HOGEHOGE'
    }
    JOB = ConcreteJob(options=OPTIONS)
    import json
    print(json.dumps(JOB.generate_items))

In summary, it looks like this = 3

Recommended Posts

Write your blackbird plugin # 002
Write your blackbird plugin # 001
Write your blackbird plugin # 003
Write a vim plugin in Python
Write a simple Vim Plugin in Python 3