diff --git a/doc/en/developer/plugins_advanced.md b/doc/en/developer/plugins_advanced.md index b5f8a8a4b..efe020842 100644 --- a/doc/en/developer/plugins_advanced.md +++ b/doc/en/developer/plugins_advanced.md @@ -16,6 +16,7 @@ Table of contents 6. [HTTP](#lib_http) 7. [DBI](#lib_dbi) 8. [Model Classes Usage](#model_class_usage) +9. [Sequence diagram](#sequence_diagram) *******
@@ -1274,4 +1275,13 @@ The following example show 4 new attributes: * *closure_custom_perfdata*: should be used to manage yourself the perfdata. * *closure_custom_threshold_check*: should be used to manage yourself the threshold check. -[Table of content (1)](#table_of_contents) \ No newline at end of file +[Table of content (1)](#table_of_contents) + +
+ +### 9. Sequence diagram + +A sequence diagram has been designed to help understand the timeline of a plugin execution. +All the explanations are [here](sequence_diagram.md) and the full diagram is [here](sequence_diagram.mmd). + +[Table of content (1)](#table_of_contents) diff --git a/doc/en/developer/sequence_diagram.md b/doc/en/developer/sequence_diagram.md new file mode 100644 index 000000000..e91d7a133 --- /dev/null +++ b/doc/en/developer/sequence_diagram.md @@ -0,0 +1,178 @@ +# Centreon Plugins sequence diagram + +## Cookbook + +The description of the diagram uses the [Mermaid](https://mermaid.js.org/) syntax, which is natively supported by +Github. You may also check out the file locally and generate the diagram with the following +[mermaid-cli](https://github.com/mermaid-js/mermaid-cli) (`mmdc`) command: + +```bash +mmdc -f -i sequence_diagram.mmd -o sequence_diagram.pdf +``` + +Other output formats such as *png* and *svg* are also available. + +## Explanation + +### Use case + +The provided sequence diagram has been written while debugging this command line: + +```bash +perl centreon_plugins.pl --plugin='cloud::azure::database::elasticpool::plugin' --mode='storage' +``` + +As explained in [plugins_advanced.md](plugins_advanced.md), each mode can use various types of counters, with various +data types and structures. Here, the `maps_counters_type` is of type **3**, which means the most complex case, when +metrics and statuses are associated to instances organized in groups. +The other types are not explained here, but you may find the keys to understanding them. + +### Side notes + +In the diagram, almost all the `.pm` files' names are constants in every use case, except for two: +- _plugin.pm_: the name is always the same by convention, but its location depends on what is given as the `--plugin` option +- _themode.pm_: stands for the mode of the plugin that is being used (given as the `--mode` option). For example, cpu.pm, memory.pm... + +### Complete diagram + +The complete diagram can be natively displayed by Github [here](sequence_diagram.mmd). + +## Interesting parts of the diagram for developers + +When you develop a new mode for a plugin, your responsibility will be to provide the necessary functions in _themode.pm_. + +### new() + +This constructor must call the inherited one (`$class->SUPER::new()`) and then add the options that are specific to this mode. + +```mermaid +sequenceDiagram + script_custom.pm ->> +themode.pm: $self->{modes}{
$self->{mode_name}
}->new() + Note right of themode.pm: Here "themode.pm" stands
for cpu.pm, uptime.pm
or whatever mode file + create participant counter.pm + themode.pm ->> +counter.pm: new() + Note right of counter.pm: counter::new() constructor
inherited by themode.pm + create participant mode.pm + counter.pm ->> +mode.pm: $class->SUPER::new() + create participant perfdata.pm + mode.pm ->> +perfdata.pm: centreon::plugins::
perfdata->new(
output => $options{output}) + Note right of perfdata.pm: Stores a reference
to the output object
Initialises thlabel + perfdata.pm -->> -mode.pm: Back from new() + mode.pm -->> -counter.pm: Back from new() + counter.pm -> counter.pm: centreon::plugins::misc::
mymodule_load(...) + Note right of counter.pm: Loads statefile.pm if necessary + counter.pm ->> +themode.pm: $self->set_counters(%options); + Note left of themode.pm: set_counters() must
define the counter's
structure + themode.pm -->> -counter.pm: Back from set_counters() + + rect rgb(230, 255, 255) + loop For each counter/subcounter + counter.pm -> counter.pm: get_threshold_prefix(
name => $counter
) + Note right of counter.pm: Builds the thresholds
label (thlabel) + counter.pm ->> options.pm: add_options() + Note right of counter.pm: Adds "very long thresholds
options" with thlabel + counter.pm ->> options.pm: add_options() + Note right of counter.pm: Adds thresholds options
with label redirecting to
the long thresholds + create participant values.pm + counter.pm ->> values.pm: $_->{obj} =
centreon::plugins::values->new(...) + Note right of values.pm: Stores references to
various objects (statefile,
output, perfdata) and initiates others + counter.pm ->> values.pm: $_->{obj}->set() + Note right of values.pm: Stores the counter's
"set" object's attributes
into values' $self
(ie $self->{obj} for counter.pm) + Note right of counter.pm: End of for each counter/subcounter + end + end + Note right of counter.pm: Still in new() + counter.pm -->> -themode.pm: Back to new() after
the inherited constructor + themode.pm ->> options.pm: add_options() + Note left of options.pm: Adds options that
are specific to the mode
such as filters + themode.pm -->> -script_custom.pm: Back from $self->
{modes}{$self->{mode_name}}
->new() to init() +``` + +### check_options() + +This method must check that all mandatory options have been given and control they're valid. + +```mermaid +sequenceDiagram + script_custom.pm ->> +themode.pm: $self->{mode}->check_options() + themode.pm ->> +counter.pm: $self->SUPER::check_options() + counter.pm ->> +mode.pm: $self->SUPER::init(%options); + mode.pm -> mode.pm: %{$self->{option_results}} =
>%{$options{option_results}}; + mode.pm -> mode.pm: Apply the default options
values when none given + mode.pm -->> -counter.pm: Back to check_options() + counter.pm -> counter.pm: Handle --list-counters option + counter.pm -> counter.pm: If type 2 counter, prepares
the macros substitutions. + rect rgb(230, 255, 255) + loop For each counter/subcounter + counter.pm ->> +values.pm: $sub_counter->{obj}->init(
option_results => $self->{option_results}) + values.pm ->> +perfdata.pm: $self->{perfdata}->threshold_validate() + perfdata.pm -> perfdata.pm: centreon::plugins::misc::parse_threshold(
threshold => $options{value}); + Note left of perfdata.pm: This function checks the
conformity of threshold
Splits into a global status and
"result_perf" (arobase, end, infinite_neg,
infinite_pos, start) + Note left of perfdata.pm: Stores the result in $self->{threshold_label}->{$options{label}} + perfdata.pm -->> -values.pm: Back to init() + values.pm -->> -counter.pm: Back to check_options() + end + end + counter.pm -> counter.pm: $self->change_macros(...) + Note right of counter.pm: Replaces all the %{macros}
with the adequate
Perl expressions for
future eval + counter.pm -> counter.pm: $self->{statefile_value}->check_options(...); + Note right of counter.pm: If statefile is used + counter.pm -->> -themode.pm: Back to check_options() + Note right of themode.pm: Checks that the mode-specific
options are valid + themode.pm -->> -script_custom.pm: Back to init() from check_options() +``` + +### set_counters() + +This method will describe how you decide to structure the collected data in order to let the plugins classes (`counter`, +`mode`, `perfdata`, `values` and `output`) handle them. + +```mermaid +sequenceDiagram + counter.pm ->> +themode.pm: $self->set_counters(%options); + Note left of themode.pm: set_counters() must
define the counter's
structure + themode.pm -->> -counter.pm: Back from set_counters() +``` + +### manage_selection() + +This method is the one that will be the most specific to the plugin and the mode you're working on since it will have to +cope with both the protocol and the data structures in input and in output. + +```mermaid +sequenceDiagram + counter.pm ->> +themode.pm: $self->manage_selection(%options) + Note left of themode.pm: Gathers the data and stores
them in the counters
structure + themode.pm -->> -counter.pm: Back from manage_selection() +``` + +### Callback functions + +> The callback functions must be defined in the corresponding _themode.pm_ file but they actually apply to objects with the **values** class (defined in the **values.pm** file). You should bear it in mind while writing these functions, to know what data you can access. + +#### closure_custom_calc + +This function receives a hash called `%options`, which contains a hash reference under `$options{new_datas}`. The function must feed `$self->{result_values}` for further processing. +The default function that will be called is `centreon::plugins::templates::catalog_functions::catalog_status_calc()`. + +```mermaid +sequenceDiagram + values.pm ->> themode.pm: $self->{closure_custom_calc}->(...) +``` + +#### closure_custom_output + +This method must return a string to be displayed in the output using data stored as attributes of `$self->{result_values}` where the available keys are the strings listed in the `key_values` entries. + +#### closure_custom_threshold_check + +This callback function can be defined to implement custom logic in the evaluation of the returned status. + +```mermaid +sequenceDiagram + values.pm ->> +themode.pm: return &{$self->{closure_custom_threshold_check}}($self, %options); + Note right of themode.pm: WARNING: This function is declared in themode.pm but is actually called as a method for class values + Note right of values.pm: If this function closure_custom_threshold_check is defined + themode.pm ->> perfdata.pm: $self->{perfdata}->threshold_check() + themode.pm -->> -values.pm: Back from closure_custom_threshold_check +``` \ No newline at end of file diff --git a/doc/en/developer/sequence_diagram.mmd b/doc/en/developer/sequence_diagram.mmd new file mode 100644 index 000000000..bcb91437a --- /dev/null +++ b/doc/en/developer/sequence_diagram.mmd @@ -0,0 +1,245 @@ +sequenceDiagram + participant centreon_plugins.pl + create participant script.pm + centreon_plugins.pl ->> script.pm: new() + centreon_plugins.pl ->> +script.pm: run() + script.pm ->> +script.pm: get_plugin() + create participant options.pm + Note over options.pm: Package centreon::plugins::options + script.pm ->> options.pm: new() + Note right of options.pm: Imports GetOptions from Getopt::Long + create participant output.pm + Note over output.pm: Package centreon::plugins::output + script.pm ->> +output.pm: new() + output.pm ->> options.pm: add_options() + Note right of output.pm: Adds options for output and perfdata + output.pm -->> -script.pm: Back from new() + script.pm ->> options.pm: set_output() + Note right of options.pm: Stores a reference to output object + script.pm ->> options.pm: add_options() + Note right of options.pm: Adds all the script options
(plugin, list-plugin, help...) + script.pm ->> options.pm: parse_options() + Note right of options.pm: Calls GetOptions(%{$self->{options}})
and empty $self->{options} + script.pm ->> options.pm: get_options() + Note right of options.pm: Stores all the following options:
('plugin', 'list_plugin', 'help', 'version', 'runas',
'environment', 'ignore_warn_msg', 'convert_args') + script.pm ->> output.pm: plugin() + Note right of output.pm: Stores the --plugin name in $self->{plugin} + script.pm ->> options.pm: get_options() + Note right of options.pm: Returns all the options from $self->{options_stored} + script.pm ->> +output.pm: check_options() + Note right of output.pm: Checks all the options obtained right before + output.pm -> output.pm: load_perfdata_extend_args() + Note right of output.pm: Handles "extend perfdata" options if present + output.pm -->> -script.pm: Back to get_plugin()
from check_options() + script.pm ->> options.pm: clean() + Note right of options.pm: Empties $self->{options_stored} + script.pm -->> -script.pm: Back to run()
from get_plugin() + script.pm -> script.pm: [several actions if
not in nominal use] + script.pm ->> +script.pm: check_relaunch() + script.pm -> script.pm: check_relaunch_get_args() + Note right of script.pm: Rewrites the command with all its arguments + script.pm -> script.pm: centreon::plugins::misc::backtick() + script.pm -->> -script.pm: End of check_relaunch() + script.pm -> script.pm: centreon::plugins::misc::
mymodule_load() + Note right of script.pm: Loads the code of the plugin + create participant plugin.pm + script.pm ->> +plugin.pm: new() + create participant script_custom.pm + plugin.pm ->> +script_custom.pm: new() + Note over script_custom.pm: Package centreon::plugins::script_custom + script_custom.pm ->> options.pm: add_options() + Note right of script_custom.pm: mode, dyn-mode, list-mode,
custommode, list-custommode,
multiple + script_custom.pm ->> options.pm: parse_options() + Note right of script_custom.pm: GetOptions(%{$self->{options}})
and empties $self->{options} + script_custom.pm ->> options.pm: get_options() + Note right of script_custom.pm: Retourne $self->{options_stored} + script_custom.pm ->> options.pm: add_help(package => $options{package},
sections => 'PLUGIN DESCRIPTION') + script_custom.pm ->> options.pm: add_help(package => __PACKAGE__, sections => 'GLOBAL OPTIONS') + script_custom.pm ->> output.pm: mode(name => $self->{mode_name}) + Note left of output.pm: $self->{mode} = $options{name} + script_custom.pm -->> -plugin.pm: Back from new() + plugin.pm -> plugin.pm: Populates $self->{modes}
with the available modes + plugin.pm -> plugin.pm: Populates $self->{custom_modes} + plugin.pm -->> -script.pm: Back from new() to run() + script.pm ->> +plugin.pm: init(help => $self->{help}, version => $self->{version}) + plugin.pm ->> options.pm: add_options() + Note right of plugin.pm: Adds options specific
to the plugin (eg
api-version) + plugin.pm ->> +script_custom.pm: $self->SUPER::
init(%options) + script_custom.pm -> script_custom.pm: display_help() && option_exit() + Note right of script_custom.pm: Displays help/version/
list-mode/list-custommode
if asked + script_custom.pm -> script_custom.pm: load_password_mgr() + script_custom.pm ->> +script_custom.pm: load_custom_mode() + script_custom.pm -> script_custom.pm: centreon::plugins::misc::
mymodule_load(...) + create participant custommode.pm + script_custom.pm ->> +custommode.pm: $self->{custom_modes}
->{$self->{custommode_name}}
->new() + custommode.pm ->> options.pm: add_options() + Note right of custommode.pm: Adds options that are
specific to the custom
mode + custommode.pm ->> options.pm: add_help() + Note right of custommode.pm: Adds options that are
specific to the custom
mode + custommode.pm -> custommode.pm: $self->{output} = $options{output}; + custommode.pm -> custommode.pm: Call constructors for
http/lwp/curl, statefile + custommode.pm -->> -script_custom.pm: Back to load_custom_mode() + script_custom.pm -->> -script_custom.pm: Back to init() + script_custom.pm -> script_custom.pm: centreon::plugins::misc::
mymodule_load(...) + Note right of script_custom.pm: Loads the code of the mode + create participant themode.pm + script_custom.pm ->> +themode.pm: $self->{modes}{
$self->{mode_name}
}->new() + Note right of themode.pm: Here "themode.pm" stands
for cpu.pm, uptime.pm
or whatever mode file + create participant counter.pm + themode.pm ->> +counter.pm: new() + Note right of counter.pm: counter::new() constructor
inherited by themode.pm + create participant mode.pm + counter.pm ->> +mode.pm: $class->SUPER::new() + create participant perfdata.pm + mode.pm ->> +perfdata.pm: centreon::plugins::
perfdata->new(
output => $options{output}) + Note right of perfdata.pm: Stores a reference
to the output object
Initialises thlabel + perfdata.pm -->> -mode.pm: Back from new() + mode.pm -->> -counter.pm: Back from new() + counter.pm -> counter.pm: centreon::plugins::misc::
mymodule_load(...) + Note right of counter.pm: Loads statefile.pm if necessary + counter.pm ->> +themode.pm: $self->set_counters(%options); + Note left of themode.pm: set_counters() must
define the counter's
structure + themode.pm -->> -counter.pm: Back from set_counters() + + rect rgb(230, 255, 255) + loop For each counter/subcounter + counter.pm -> counter.pm: get_threshold_prefix(
name => $counter
) + Note right of counter.pm: Builds the thresholds
label (thlabel) + counter.pm ->> options.pm: add_options() + Note right of counter.pm: Adds "very long thresholds
options" with thlabel + counter.pm ->> options.pm: add_options() + Note right of counter.pm: Adds thresholds options
with label redirecting to
the long thresholds + create participant values.pm + counter.pm ->> values.pm: $_->{obj} =
centreon::plugins::values->new(...) + Note right of values.pm: Stores references to
various objects (statefile,
output, perfdata) and initiates others + counter.pm ->> values.pm: $_->{obj}->set() + Note right of values.pm: Stores the counter's
"set" object's attributes
into values' $self
(ie $self->{obj} for counter.pm) + Note right of counter.pm: End of for each counter/subcounter + end + end + Note right of counter.pm: Still in new() + counter.pm -->> -themode.pm: Back to new() after
the inherited constructor + themode.pm ->> options.pm: add_options() + Note left of options.pm: Adds options that
are specific to the mode
such as filters + themode.pm -->> -script_custom.pm: Back from $self->
{modes}{$self->{mode_name}}
->new() to init() + script_custom.pm ->> options.pm: add_help(...) + Note right of script_custom.pm: Adds help from "MODE"
section from the mode
if --help option is provided + script_custom.pm ->> options.pm: parse_options() + Note right of script_custom.pm: Calls GetOptions(%{$self->{options}})
and empty $self->{options} + script_custom.pm ->> options.pm: get_options() + Note right of script_custom.pm: Stores all the mode-specific options.
At this point, all the
options have been parsed
and stored in $self->{option_results} + script_custom.pm -> script_custom.pm: $self->{pass_mgr}->manage_options() + script_custom.pm -> script_custom.pm: $self->{custommode_current}->set_options(option_results => $self->{option_results}); + script_custom.pm -> script_custom.pm: $self->{custommode_current}->set_defaults(default => $self->{customdefault}); + script_custom.pm -> script_custom.pm: $self->{custommode_current}->check_options() + script_custom.pm ->> +themode.pm: $self->{mode}->check_options() + themode.pm ->> +counter.pm: $self->SUPER::check_options() + counter.pm ->> +mode.pm: $self->SUPER::init(%options); + mode.pm -> mode.pm: %{$self->{option_results}} =
>%{$options{option_results}}; + mode.pm -> mode.pm: Apply the default options
values when none given + mode.pm -->> -counter.pm: Back to check_options() + counter.pm -> counter.pm: Handle --list-counters option + counter.pm -> counter.pm: If type 2 counter, prepares
the macros substitutions. + rect rgb(230, 255, 255) + loop For each counter/subcounter + counter.pm ->> +values.pm: $sub_counter->{obj}->init(
option_results => $self->{option_results}) + values.pm ->> +perfdata.pm: $self->{perfdata}->threshold_validate() + perfdata.pm -> perfdata.pm: centreon::plugins::misc::parse_threshold(
threshold => $options{value}); + Note left of perfdata.pm: This function checks the
conformity of threshold
Splits into a global status and
"result_perf" (arobase, end, infinite_neg,
infinite_pos, start) + Note left of perfdata.pm: Stores the result in $self->{threshold_label}->{$options{label}} + perfdata.pm -->> -values.pm: Back to init() + values.pm -->> -counter.pm: Back to check_options() + end + end + counter.pm -> counter.pm: $self->change_macros(...) + Note right of counter.pm: Replaces all the %{macros}
with the adequate
Perl expressions for
future eval + counter.pm -> counter.pm: $self->{statefile_value}->check_options(...); + Note right of counter.pm: If statefile is used + counter.pm -->> -themode.pm: Back to check_options() + Note right of themode.pm: Checks that the mode-specific
options are valid + themode.pm -->> -script_custom.pm: Back to init() from check_options() + script_custom.pm -->> -plugin.pm: Back from $self->SUPER::init(%options) + plugin.pm -->> -script.pm: Back from init() to run() + script.pm ->> +plugin.pm: $plugin->run() + Note right of plugin.pm: No run() defined => call inherited + plugin.pm ->> +script_custom.pm: run() + Note right of script_custom.pm: Displays the disco-format if asked + Note right of script_custom.pm: Displays the disco-show if asked + script_custom.pm ->> +themode.pm: $self->{mode}->run(...) + Note right of themode.pm: No run() defined => call inherited + themode.pm ->> +counter.pm: run(...) + counter.pm ->> +themode.pm: $self->manage_selection(%options) + Note left of themode.pm: Gathers the data and stores
them in the counters
structure + themode.pm -->> -counter.pm: Back from manage_selection() + counter.pm -> counter.pm: $self->{statefile_value}->read(statefile => $self->{cache_name}) + Note right of counter.pm: Reads statefile (cache) if needed + rect rgb(230, 255, 255) + loop For each $self->{maps_counters_type} + counter.pm -> counter.pm: $self->run_global(...) + Note right of counter.pm: If counter is of type 0.
Not detailed here. + counter.pm -> counter.pm: $self->run_instances(...) + Note right of counter.pm: If counter is of type 1.
Not detailed here. + counter.pm -> counter.pm: $self->run_group(...) + Note right of counter.pm: If counter is of type 2.
Not detailed here. + counter.pm ->> +counter.pm: $self->run_multiple(...) + Note right of counter.pm: If counter is of type 3 + counter.pm ->> output.pm: output_add(...) + Note right of counter.pm: Sets the default output and status to OK + rect rgb(255, 230, 255) + loop For each sub-entry + counter.pm ->> +counter.pm: $self->call_object_callback( method_name => $options{config}->{cb_long_output}, instance => $instance, instance_value => $self->{$options{config}->{name}}->{$instance} ) + Note right of counter.pm: Calls the callback function given as the cb_long_output attribute of the current entry of $self->{maps_counters_type} + counter.pm -->> -counter.pm: Back from call_object_callback() to run_multiple() + counter.pm ->> +output.pm: $self->{output}->output_add(long_msg => ) + output.pm -->> -counter.pm: Back from output_add() to run_multiple() + counter.pm ->> +counter.pm: $self->call_object_callback(method_name => $options{config}->{cb_prefix_output}, instance => $instance, instance_value => $self->{$options{config}->{name}}->{$instance}) + Note right of counter.pm: Calls the callback function given as the cb_prefix_output attribute of the current entry of $self->{maps_counters_type} + counter.pm -->> -counter.pm: Back from call_object_callback() to run_multiple() + rect rgb(255, 255, 230) + loop For each group + counter.pm ->> +counter.pm: $self->run_multiple_instances(config => $group, multiple_parent => $multiple, instance_parent => $instance, indent_long_output => $indent_long_output); + counter.pm ->> counter.pm: $self->call_object_callback(method_name => $options{config}->{cb_init}) + Note left of counter.pm: Calls the callback function given as the cb_init attribute of the current entry of $self->{maps_counters_type} + counter.pm ->> output.pm: $self->{output}->use_new_perfdata() + Note right of counter.pm: Returns 1 if the new labels (nlabel) must be used + loop For each instance under that group + loop For each configured counter in that group + counter.pm ->> values.pm: $obj->set(instance => $instance); + Note right of values.pm: Sets the $obj instance attribute to the given value + counter.pm ->> +values.pm: $obj->execute( new_datas => $self->{new_datas}, values => $self->{$options{config}->{name}}->{$id}) + loop For each item in "key_values" + Note right of values.pm: exit the loop if "no_values" given + values.pm ->> themode.pm: $self->{closure_custom_calc}->(...) + Note right of values.pm: If this function is defined + Note right of values.pm: Else + values.pm ->> +values.pm: $self->calc() + values.pm ->> values.pm: Copies the "key_value" entry (eg. display, storage_used, ...) or the diff between last check and current check or the ratio into $self->{result_values} + values.pm -->> -values.pm: Back to execute() + end + values.pm -->> -counter.pm: Back from execute() + counter.pm ->> +values.pm: $obj->threshold_check() + values.pm ->> +themode.pm: return &{$self->{closure_custom_threshold_check}}($self, %options); + Note right of themode.pm: WARNING: This function is declared in themode.pm but is actually called as a method for class values + Note right of values.pm: If this function closure_custom_threshold_check is defined + themode.pm ->> perfdata.pm: $self->{perfdata}->threshold_check() + themode.pm -->> -values.pm: Back from closure_custom_threshold_check + values.pm ->> perfdata.pm: return $self->{perfdata}->threshold_check() + Note right of values.pm: If this function closure_custom_threshold_check is NOT defined + values.pm -->> -counter.pm: Back from threshold_check() + end + end + counter.pm -->> -counter.pm: Back from run_multiple_instances() + Note right of counter.pm: If the group's type is 1 + counter.pm ->> counter.pm: $self->run_global( config => $group, multiple_parent => $multiple, called_multiple => 1, force_instance => $instance, indent_long_output => $indent_long_output) + Note right of counter.pm: If the group's type is 0.
Not detailed here. + end + end + end + end + counter.pm -->> -counter.pm: Back from run_multiple() + end + end + counter.pm -->> -themode.pm: Back from run() + themode.pm -->> -script_custom.pm: Back from run() + plugin.pm -->> -script.pm: Back from run() to run() + script.pm -->> -centreon_plugins.pl: End of run() \ No newline at end of file