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.
As a rough procedure,
It is like this.
The base class is contained in the blackbird body,
pip install blackbird
You can easily get it at.
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.
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.
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
.
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
datetime.datetime
instance with the acquisition time setself.config
contains the contents written in the config file in dict format.Does not need to be implemented on the plugin developer side.
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 with
ConcreteItem.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.
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.
Validator.spec
[]
of __spec
must be the name of the plugin module itself__name__
string ()
, it will be a required parameter because there is no default value.string (default ='HOGEHOGE')
, the default value will be a character string called HOGEHOGE, so it will be optional.port = integer(0, 65535, default=80)
__spec
with docstring, but considering the integration of the format method, it's easier to pass a string with tuple and use a multi-line string.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