|
|
## EAR Data Center Monitoring
|
|
|
|
|
|
Plugin Manager is a small framework with its own thread that opens shared objects (or plugins) and executes their functions periodically. These plugins can communicate with each other through a tag system.
|
|
|
|
|
|
### Creating a plugin
|
|
|
|
|
|
These plugin periodic functions have to have concrete name. In plugin_manager.h you can find helper macros to define the functions and maintain your plugins updated in case of a change:
|
|
|
|
|
|
```
|
|
|
#define declr_up_get_tag() void up_get_tag (cchar **tag, cchar **tags_deps)
|
|
|
#define declr_up_action_init(suffix) char * up_action_init##suffix (cchar *tag, void **data_alloc, void *data)
|
|
|
#define declr_up_action_periodic(suffix) char * up_action_periodic##suffix (cchar *tag, void *data)
|
|
|
#define declr_up_post_data() char * up_post_data (cchar *msg, void *data)
|
|
|
|
|
|
#define is_tag(t) (strcmp(t, tag) == 0)
|
|
|
#define is_msg(t) (strcmp(t, msg) == 0)
|
|
|
```
|
|
|
|
|
|
The function `get_tag` is in charge of returning the plugin own tag and its dependency tags. A tag matches the name of the shared object file (without the extension). The dependency tags allows the Plugin Manager to search and open the tagged plugins automatically. The format is a tag list sepparated by plus signs. Example:
|
|
|
|
|
|
```
|
|
|
declr_up_get_tag()
|
|
|
{
|
|
|
*tag = "some_test";
|
|
|
*tags_deps = "dependency1+!dependency2";
|
|
|
}
|
|
|
```
|
|
|
|
|
|
If a dependency tag starts with an exclamation mark '!', it means that dependency is mandatory for the loading plugin, and in case it is not resolved the loading plugin will be disabled. The symbol '<' tells the Plugin Manager to inherit the timing of the dependant plugin.
|
|
|
|
|
|
The function `action_periodic` is the core function and is called periodically at a time specified when loading the framework as we will se below. It receives a tag and a data pointer associated with that tag. The received tag could be the self tag or the tag of other plugins. Below you will find more about the calling pipeline and the priority system.
|
|
|
|
|
|
Examples of action_periodic function types:
|
|
|
```
|
|
|
declr_up_action_periodic(_tag1)
|
|
|
{
|
|
|
type1_t *d = (type1_t *) data;
|
|
|
// work
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
declr_up_action_periodic()
|
|
|
{
|
|
|
if (is_tag("tag2")) {
|
|
|
type2_t *d = (type2_t *) data;
|
|
|
// work
|
|
|
}
|
|
|
return NULL;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
You can use the macro `is_tag` to distinguish between tags or use suffix in the declaration macro to be called only for specific tags, freeing your code from conditionals. The `action_periodic_init` is called once at the beginning of the execution and serves as data allocator through `data_alloc` pointer. These functions return a char pointer containing a message to print or NULL in case you don't want to print anything.
|
|
|
|
|
|
The returning char is a message that Plugin Manager will print in case is not NULL. You can add some modifiers at the beginning of the message:
|
|
|
- `[D]` disables the plugin. It also re-activates the dependency system and could disable dependant plugins.
|
|
|
- `[=]` pauses the periodic call.
|
|
|
- `[X]` closes the Plugin Manager main thread.
|
|
|
|
|
|
Finally, `post_data` allows to receive external data to the plugin. In example, if Plugin Manager is being used by the EARD, when a job starts you could send a message to the framework containing the job and step IDs. By now you can distinguish the messages by `is_msg` macro. Maybe in the near future we implement the suffix system too.
|
|
|
|
|
|
You can find examples of plugins in `data_center_monitoring/plugins` folder.
|
|
|
|
|
|
## The Plugin Manager framework
|
|
|
|
|
|
By now these are the functions of the framework:
|
|
|
|
|
|
```
|
|
|
// Init as main binary function
|
|
|
int plugin_manager_main(int argc, char *argv[]);
|
|
|
|
|
|
// Init as a component of a binary
|
|
|
int plugin_manager_init(char *files, char *paths);
|
|
|
|
|
|
// Closes Plugin Manager main thread.
|
|
|
void plugin_manager_close();
|
|
|
|
|
|
// Wait until Plugin Manager exits.
|
|
|
void plugin_manager_wait();
|
|
|
|
|
|
// Asking for an action. Intended to be called from plugins.
|
|
|
void *plugin_manager_action(cchar *tag);
|
|
|
|
|
|
// Passing data to plugins. Intended to be called outside PM.
|
|
|
void plugin_mananger_post(cchar *msg, void *data);
|
|
|
```
|
|
|
|
|
|
There are two initializing functions: `plugin_manager_main` and `plugin_manager_init`. `plugin_manager_main` receives the binary main arguments and `plugin_manager_init` a list of loaded plugins and search paths. This is an example of binary arguments and its format:
|
|
|
|
|
|
```
|
|
|
./bin --plugins=metrics.so:2000+periodic_metrics.so:4000 --paths=path/to/plugins1:path/to/plugins2
|
|
|
```
|
|
|
|
|
|
The list of plugins contains their calling time in milliseconds. Additional colon can be provided to pass information to a plugin. In that case
|
|
|
that information would be delivered as string through the `data` pointer in `up_action_init` function. In example:
|
|
|
|
|
|
```
|
|
|
./bin --plugins=metrics.so:2000+periodic_metrics.so:4000:config_message --paths=path/to/plugins1:path/to/plugins2
|
|
|
```
|
|
|
|
|
|
In this example, `metrics.so` would be called every 2 seconds and also would feed `periodic_metrics.so` with metrics data. But `periodic_metrics.so` with its own tag and allocated data, would be called every 4 seconds. In case the time is not specified, is considered an `init` plugin.
|
|
|
|
|
|
As previously explained, `plugin_mananger_post` is used to pass information to the plugins. `plugin_manager_action` is intended to be called from plugins, to call other plugin specificed by its tag and return its data. Lastly `plugin_manager_wait` waits indefinitely until the end of the Plugin Manager thread. The usage is the following:
|
|
|
|
|
|
```
|
|
|
Usage: ./bin [OPTIONS]
|
|
|
|
|
|
Options:
|
|
|
--plugins List of comma separated plugins to load.
|
|
|
--paths List of comma separated priority paths to search plugins.
|
|
|
--verbose Show how the things are going internally.
|
|
|
--silence Hide messages returned by plugins.
|
|
|
--help If you see it you already typed --help.
|
|
|
```
|
|
|
|
|
|
## Calling pipeline and priority system
|
|
|
|
|
|
When time is up for a specific plugin, in example `specific.so`, its `action_periodic` or `action_periodic_specific` function is called. After the return, the `action_periodic` or `action_periodic_specific` function of the rest of the other plugins are called with the `specific` tag and `specific` data pointer. In case of `action_init` or if multiple plugins share the periodic time, the calling order is determined by a priority system.
|
|
|
|
|
|
The priority system takes into the account the order written in `--plugins` parameter, but also the dependencies. If a plugin A is a dependency of plugin B, plugin A will be called before. If a plugin C was written before plugin D and both share the same periodic time, plugin C will be called before plugin D.
|
|
|
|
|
|
If a Plugin C is written before plugin D in the `--plugins` parameter, but C depends on D, D will be called before. These rare cases are contemplated in the dependency system algorithmics.
|
|
|
|
|
|
## FAQ
|
|
|
|
|
|
- **Can I load the same plugin twice?** No.
|
|
|
- **Is the tag mandatory value?** Yes, all the plugins require a tag.
|
|
|
- **And the dependency tags?** Can be set to NULL if the plugin does not have any dependency.
|
|
|
- **Do I have to specify the time of a plugin in the dependency list?** No, is not recommended. A plugin which is loaded by the dependency list instead using the `--plugins` parameter inherits the dependent plugin time if using the special character '<' at the beginning of the string.
|
|
|
- **If none of the dependencies are resolved, the plugin periodic function will be called anyways?** Depends if some of the dependencies are mandatory, specified by the exclamation mark (!).
|
|
|
- **What happens if a plugin has periodic time specified but haven't defined a periodic function?** If there is no periodic function, nothing will be called.
|
|
|
- **Do I have to define all the API functions in the plugin?** No, only those necessary for the correct plugin functionality. The `get_tag` function is the exception because the tag is a mandatory value.
|
|
|
- **Can `action_init` function be defined but `action_periodic` not?** Yes. Sometimes you want to perform an action just once and you can do it in the init function. In example, the job of the plugin `conf.so` is to read `ear.conf` and pass the configuration structure to the rest of loading plugins.
|
|
|
- **For a plugin which does not allocate data, is its periodic function called?** Yes, if it's defined. But the NULL value in the allocated data pointer disallows any information exchange, so periodic function of other plugins wont be called.
|
|
|
- **If a plugin has defined the a function `action_periodic_specific` for the tag `specific`, but also the general `action_periodic`, which of the two would be called?** For the `specific` tag `action_periodic_specific` would be called. For the rest of the tags the general `action_periodic`. |
|
|
\ No newline at end of file |