doc(dev): add plugins sequence diagram

Refs: CTOR-1456
This commit is contained in:
omercier 2025-03-25 17:51:31 +01:00
parent 75873668bf
commit 453c0dc239
2 changed files with 418 additions and 0 deletions

View File

@ -0,0 +1,173 @@
# 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 also may checkout the file locally and generate the diagram with
[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). Eg. cpu.pm, memory.pm, ...
## Interesting diagram parts 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}{<br/>$self->{mode_name}<br/>}->new()
Note right of themode.pm: Here "themode.pm" stands<br/>for cpu.pm, uptime.pm<br/>or whatever mode file
create participant counter.pm
themode.pm ->> +counter.pm: new()
Note right of counter.pm: counter::new() constructor<br/>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::<br/>perfdata->new(<br/>output => $options{output})
Note right of perfdata.pm: Stores a reference<br/>to the output object<br/>Initialises thlabel
perfdata.pm -->> -mode.pm: Back from new()
mode.pm -->> -counter.pm: Back from new()
counter.pm -> counter.pm: centreon::plugins::misc::<br/>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<br/>define the counter's<br/>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(<br/>name => $counter<br/>)
Note right of counter.pm: Builds the thresholds<br/>label (thlabel)
counter.pm ->> options.pm: add_options()
Note right of counter.pm: Adds "very long thresholds<br/>options" with thlabel
counter.pm ->> options.pm: add_options()
Note right of counter.pm: Adds thresholds options<br/>with label redirecting to<br/>the long thresholds
create participant values.pm
counter.pm ->> values.pm: $_->{obj} =<br/>centreon::plugins::values->new(...)
Note right of values.pm: Stores references to<br/>various objects (statefile,<br/>output, perfdata) and initiates others
counter.pm ->> values.pm: $_->{obj}->set()
Note right of values.pm: Stores the counter's<br/>"set" object's attributes<br/>into values' $self<br/>(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<br/>the inherited constructor
themode.pm ->> options.pm: add_options()
Note left of options.pm: Adds options that<br/>are specific to the mode<br/>such as filters
themode.pm -->> -script_custom.pm: Back from $self-><br/>{modes}{$self->{mode_name}}<br/>->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}} =<br/>>%{$options{option_results}};
mode.pm -> mode.pm: Apply the default options<br/>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<br/>the macros substitutions.
rect rgb(230, 255, 255)
loop For each counter/subcounter
counter.pm ->> +values.pm: $sub_counter->{obj}->init(<br/>option_results => $self->{option_results})
values.pm ->> +perfdata.pm: $self->{perfdata}->threshold_validate()
perfdata.pm -> perfdata.pm: centreon::plugins::misc::parse_threshold(<br/>threshold => $options{value});
Note left of perfdata.pm: This function checks the<br/>conformity of threshold<br/>Splits into a global status and<br/>"result_perf" (arobase, end, infinite_neg,<br/>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}<br/>with the adequate<br/>Perl expressions for<br/>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<br/>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<br/>define the counter's<br/>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<br/>them in the counters<br/>structure
themode.pm -->> -counter.pm: Back from manage_selection()
```
### Callback functions
> The callback functions must be defined in _themode.pm_ but actually apply to objects of **values** class.
#### closure_custom_calc
```mermaid
sequenceDiagram
values.pm ->> themode.pm: $self->{closure_custom_calc}->(...)
```
#### closure_custom_output
```perl
return $self->{closure_custom_output}->($self);
```
#### 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
```

View File

@ -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<br/>(plugin, list-plugin, help...)
script.pm ->> options.pm: parse_options()
Note right of options.pm: Calls GetOptions(%{$self->{options}})<br/> and empty $self->{options}
script.pm ->> options.pm: get_options()
Note right of options.pm: Stores all the following options:<br/>('plugin', 'list_plugin', 'help', 'version', 'runas',<br/>'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()<br/>from check_options()
script.pm ->> options.pm: clean()
Note right of options.pm: Empties $self->{options_stored}
script.pm -->> -script.pm: Back to run()<br/>from get_plugin()
script.pm -> script.pm: [several actions if<br/>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::<br/>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,<br/>custommode, list-custommode,<br/>multiple
script_custom.pm ->> options.pm: parse_options()
Note right of script_custom.pm: GetOptions(%{$self->{options}})<br/>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},<br/> 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}<br/>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<br/>to the plugin (eg<br/>api-version)
plugin.pm ->> +script_custom.pm: $self->SUPER::<br/>init(%options)
script_custom.pm -> script_custom.pm: display_help() && option_exit()
Note right of script_custom.pm: Displays help/version/<br/>list-mode/list-custommode<br/>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::<br/>mymodule_load(...)
create participant custommode.pm
script_custom.pm ->> +custommode.pm: $self->{custom_modes}<br/>->{$self->{custommode_name}}<br/>->new()
custommode.pm ->> options.pm: add_options()
Note right of custommode.pm: Adds options that are<br/>specific to the custom<br/>mode
custommode.pm ->> options.pm: add_help()
Note right of custommode.pm: Adds options that are<br/>specific to the custom<br/>mode
custommode.pm -> custommode.pm: $self->{output} = $options{output};
custommode.pm -> custommode.pm: Call constructors for<br/>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::<br/>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}{<br/>$self->{mode_name}<br/>}->new()
Note right of themode.pm: Here "themode.pm" stands<br/>for cpu.pm, uptime.pm<br/>or whatever mode file
create participant counter.pm
themode.pm ->> +counter.pm: new()
Note right of counter.pm: counter::new() constructor<br/>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::<br/>perfdata->new(<br/>output => $options{output})
Note right of perfdata.pm: Stores a reference<br/>to the output object<br/>Initialises thlabel
perfdata.pm -->> -mode.pm: Back from new()
mode.pm -->> -counter.pm: Back from new()
counter.pm -> counter.pm: centreon::plugins::misc::<br/>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<br/>define the counter's<br/>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(<br/>name => $counter<br/>)
Note right of counter.pm: Builds the thresholds<br/>label (thlabel)
counter.pm ->> options.pm: add_options()
Note right of counter.pm: Adds "very long thresholds<br/>options" with thlabel
counter.pm ->> options.pm: add_options()
Note right of counter.pm: Adds thresholds options<br/>with label redirecting to<br/>the long thresholds
create participant values.pm
counter.pm ->> values.pm: $_->{obj} =<br/>centreon::plugins::values->new(...)
Note right of values.pm: Stores references to<br/>various objects (statefile,<br/>output, perfdata) and initiates others
counter.pm ->> values.pm: $_->{obj}->set()
Note right of values.pm: Stores the counter's<br/>"set" object's attributes<br/>into values' $self<br/>(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<br/>the inherited constructor
themode.pm ->> options.pm: add_options()
Note left of options.pm: Adds options that<br/>are specific to the mode<br/>such as filters
themode.pm -->> -script_custom.pm: Back from $self-><br/>{modes}{$self->{mode_name}}<br/>->new() to init()
script_custom.pm ->> options.pm: add_help(...)
Note right of script_custom.pm: Adds help from "MODE"<br/>section from the mode<br/>if --help option is provided
script_custom.pm ->> options.pm: parse_options()
Note right of script_custom.pm: Calls GetOptions(%{$self->{options}})<br/> and empty $self->{options}
script_custom.pm ->> options.pm: get_options()
Note right of script_custom.pm: Stores all the mode-specific options.<br/>At this point, all the<br/>options have been parsed<br/>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}} =<br/>>%{$options{option_results}};
mode.pm -> mode.pm: Apply the default options<br/>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<br/>the macros substitutions.
rect rgb(230, 255, 255)
loop For each counter/subcounter
counter.pm ->> +values.pm: $sub_counter->{obj}->init(<br/>option_results => $self->{option_results})
values.pm ->> +perfdata.pm: $self->{perfdata}->threshold_validate()
perfdata.pm -> perfdata.pm: centreon::plugins::misc::parse_threshold(<br/>threshold => $options{value});
Note left of perfdata.pm: This function checks the<br/>conformity of threshold<br/>Splits into a global status and<br/>"result_perf" (arobase, end, infinite_neg,<br/>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}<br/>with the adequate<br/>Perl expressions for<br/>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<br/>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<br/>them in the counters<br/>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.<br/>Not detailed here.
counter.pm -> counter.pm: $self->run_instances(...)
Note right of counter.pm: If counter is of type 1.<br/>Not detailed here.
counter.pm -> counter.pm: $self->run_group(...)
Note right of counter.pm: If counter is of type 2.<br/>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 => <previous result>)
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.<br/>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()