20. Modules

Overview

It is possible to enhance Zabbix frontend functionality by adding 3rd party modules or by developing your own modules without the need to change the source code of Zabbix.

Note that the module code will run with the same privileges as Zabbix source code. This means:

  • 3rd party modules can be harmful. You must trust the modules you are installing;

  • Errors in a 3rd party module code may crash the frontend. If this happens, just remove the module code from the frontend. As soon as you reload Zabbix frontend, you’ll see a note saying that some modules are absent. Go to Module administration (in AdministrationGeneralModules) and click Scan directory again to remove non-existent modules from the database.

Installation

Please always read the installation manual for a particular module. It is recommended to install new modules one by one to catch failures easily.

Just before you install a module:

  • Make sure you have downloaded the module from a trusted source. Installation of harmful code may lead to consequences, such as data loss

  • Different versions of the same module (same ID) can be installed in parallel, but only a single version can be enabled at once

Steps to install a module:

  • Unpack your module within its own folder in the modules folder of the Zabbix frontend

  • Ensure the your module folder contains at least the manifest.json file

  • Navigate to Module administration and click the Scan directory button

  • New module will appear in the list along with its version, author, description and status

  • Enable module by clicking on its status

Troubleshooting:

ProblemSolution
Module did not appear in the listMake sure that the manifest.json file exists in modules/your-module/ folder of the Zabbix frontend. If it does that means the module does not suit the current Zabbix version. If manifest.json file does not exist, you have probably unpacked in the wrong directory.
Frontend crashedThe module code is not compatible with the current Zabbix version or server configuration. Please delete module files and reload the frontend. You’ll see a notice that some modules are absent. Go to Module administration and click Scan directory again to remove non-existent modules from the database.
Error message about identical namespace, ID or actions appearsNew module tried to register a namespace, ID or actions which are already registered by other enabled modules. Disable the conflicting module (mentioned in error message) prior to enabling the new one.
Technical error messages appearReport errors to the developer of the module.

Developing modules

Modules are written in PHP language. Model-view-controller (MVC) software pattern design is preferred, as it is also used in Zabbix frontend and will ease the development. PHP strict typing is also welcome but not mandatory.

Please note that with modules you can easily add new menu items and respective views and actions to Zabbix frontend. Currently it is not possible to register new API or create new database tables through modules.

Module structure

Each module is a directory (placed within the modules directory) with sub-directories containing controllers, views and any other code:

  1. example_module_directory/ (required)
  2. manifest.json (required) Metadata and action definition.
  3. Module.php Module initialization and event handling.
  4. actions/ Action controller files.
  5. SomethingView.php
  6. SomethingCreate.php
  7. SomethingDelete.php
  8. data_export/
  9. ExportAsXml.php
  10. ExportAsExcel.php
  11. views/ View files.
  12. example.something.view.php
  13. example.something.delete.php
  14. js/ JavaScript files used in views.
  15. example.something.view.js.php
  16. partials/ View partial files.
  17. example.something.reusable.php
  18. js/ JavaScript files used in partials.
  19. example.something.reusable.js.php

As you can see, the only mandatory file within the custom module directory is manifest.json. The module will not register without this file. Module.php is responsible for registering menu items and processing events such as ‘onBeforeAction’ and ‘onTerminate’. The actions, views and partials directories contain PHP and JavaScript code needed for module actions.

Naming convention

Before you create a module, it is important to agree on the naming convention for different module items such as directories and files so that we could keep things well organized. You can also find examples above, in the Module structure section.

ItemNaming rulesExample
Module directoryLowercase [a-z], underscore and decimal digitsexample_v2
Action subdirectoriesLowercase [a-z] and underscore characterdata_export
Action filesCamelCase, ending with action typeSomethingView.php
View and partial filesLowercase [a-z]
Words separated with dot
Prefixed by module. followed by module name
Ending with action type and .php file extension
module.example.something.view.php
Javascript filesThe same rules apply as for view and partial files, except the .js.php file extension.module.example.something.view.js.php

Note that the ‘module’ prefix and name inclusion is mandatory for view and partial file names, unless you need to override Zabbix core views or partials. This rule, however, does not apply to action file names.

Manifest preparation

Each module is expected to have a manifest.json file with the following fields in JSON format:

ParameterRequiredTypeDefaultDescription
manifest_versionYesDouble-Manifest version of the module. Currently supported version is 1.
idYesString-Module ID. Only one module with given ID can be enabled at the same time.
nameYesString-Module name as displayed in the Administration section.
versionYesString-Module version as displayed in the Administration section.
namespaceYesString-PHP namespace for Module.php and action classes.
authorNoString“”Module author as displayed in the Administration section.
urlNoString“”Module URL as displayed in the Administration section.
descriptionNoString“”Module description as displayed in the Administration section.
actionsNoObject{}Actions to register with this module. See Actions.
configNoObject{}Module configuration.

For reference, please see an example of manifest.json in the Reference section.

Actions

The module will have control over frontend actions defined within the actions object in the manifest.json file. This way new actions are defined. In the same way you may redefine existing actions. Each key of actions should represent the action name and the corresponding value should contain class and optionally layout and view keys.

One action is defined by four counterparts: name, controller, view and layout. Data validation and preparation is typically done in the controller, output formatting is done in the view or partials, and the layout is responsible for decorating the page with elements such as menu, header, footer and others.

Module actions must be defined in the manifest.json file as actions object:

ParameterRequiredTypeDefaultDescription
keyYesString-Action name, in lowercase [a-z], separating words with dot.
classYesString-Action class name, including subdirectory path (if used) within the actions directory.
layoutNoString“layout.htmlpage”Action layout.
viewNoStringnullAction view.

There are several predefined layouts, like layout.json or layout.xml. These are intended for actions which produce different result than an HTML. You may explore predefined layouts in the app/views/ directory or even create your own.

Sometimes it is necessary to only redefine the view part of some action leaving the controller intact. In such case just place the necessary view and/or partial files inside the views directory of the module.

For reference, please see an example action controller file in the Reference section. Please do not hesitate to explore current actions of Zabbix source code, located in the app/ directory.

Module.php

This optional PHP file is responsible for module initialization as well as event handling. Class ‘Module’ is expected to be defined in this file, extending base class \Core\CModule. The Module class must be defined within the namespace specified in the manifest.json file.

  1. <?php
  2. namespace Modules\Example;
  3. use Core\CModule as BaseModule;
  4. class Module extends BaseModule {
  5. ...
  6. }

For reference, please see an example of Module.php in the Reference section.

Reference

This section contains basic versions of different module elements introduced in the previous sections.

manifest.json

  1. {
  2. "manifest_version": 1.0,
  3. "id": "example_module",
  4. "name": "Example module",
  5. "version": "1.0",
  6. "namespace": "Example",
  7. "author": "John Smith",
  8. "url": "http://module.example.com",
  9. "description": "Short description of the module.",
  10. "actions": {
  11. "example.something.view": {
  12. "class": "SomethingView",
  13. "view": "module.example.something.view"
  14. },
  15. "example.something.create": {
  16. "class": "SomethingCreate",
  17. "layout": null
  18. },
  19. "example.something.delete": {
  20. "class": "SomethingDelete",
  21. "layout": null
  22. },
  23. "example.something.export.xml": {
  24. "class": "data_export/ExportAsXml",
  25. "layout": null
  26. },
  27. "example.something.export.excel": {
  28. "class": "data_export/ExportAsExcel",
  29. "layout": null
  30. }
  31. },
  32. "config": {
  33. "username": "john_smith"
  34. }
  35. }

Module.php

  1. <?php declare(strict_types = 1);
  2. namespace Modules\Example;
  3. use APP;
  4. use CController as CAction;
  5. /**
  6. * Please see Core\CModule class for additional reference.
  7. */
  8. class Module extends \Core\CModule {
  9. /**
  10. * Initialize module.
  11. */
  12. public function init(): void {
  13. // Initialize main menu (CMenu class instance).
  14. APP::Component()->get('menu.main')
  15. ->findOrAdd(_('Reports'))
  16. ->getSubmenu()
  17. ->add((new \CMenuItem(_('Example wide report')))
  18. ->setAction('example.report.wide.php')
  19. )
  20. ->add((new \CMenuItem(_('Example narrow report')))
  21. ->setAction('example.report.narrow.php')
  22. );
  23. }
  24. /**
  25. * Event handler, triggered before executing the action.
  26. *
  27. * @param CAction $action Action instance responsible for current request.
  28. */
  29. public function onBeforeAction(CAction $action): void {
  30. }
  31. /**
  32. * Event handler, triggered on application exit.
  33. *
  34. * @param CAction $action Action instance responsible for current request.
  35. */
  36. public function onTerminate(CAction $action): void {
  37. }
  38. }

Action controller

  1. <?php declare(strict_types = 1);
  2. namespace Modules\Example\Actions;
  3. use CControllerResponseData;
  4. use CControllerResponseFatal;
  5. use CController as CAction;
  6. /**
  7. * Example module action.
  8. */
  9. class SomethingView extends CAction {
  10. /**
  11. * Initialize action. Method called by Zabbix core.
  12. *
  13. * @return void
  14. */
  15. public function init(): void {
  16. /**
  17. * Disable SID (Sessoin ID) validation. Session ID validation should only be used for actions which involde data
  18. * modification, such as update or delete actions. In such case Session ID must be presented in the URL, so that
  19. * the URL would expire as soon as the session expired.
  20. */
  21. $this->disableSIDvalidation();
  22. }
  23. /**
  24. * Check and sanitize user input parameters. Method called by Zabbix core. Execution stops if false is returned.
  25. *
  26. * @return bool true on success, false on error.
  27. */
  28. protected function checkInput(): bool {
  29. $fields = [
  30. 'name' => 'required|string',
  31. 'email' => 'required|string',
  32. 'phone' => 'string'
  33. ];
  34. // Only validated data will further be available using $this->hasInput() and $this->getInput().
  35. $ret = $this->validateInput($fields);
  36. if (!$ret) {
  37. $this->setResponse(new CControllerResponseFatal());
  38. }
  39. return $ret;
  40. }
  41. /**
  42. * Check if the user has permission to execute this action. Method called by Zabbix core.
  43. * Execution stops if false is returned.
  44. *
  45. * @return bool
  46. */
  47. protected function checkPermissions(): bool {
  48. $permit_user_types = [USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN];
  49. return in_array($this->getUserType(), $permit_user_types);
  50. }
  51. /**
  52. * Prepare the response object for the view. Method called by Zabbix core.
  53. *
  54. * @return void
  55. */
  56. protected function doAction(): void {
  57. $contacts = $this->getInput('email');
  58. if ($this->hasInput('phone')) {
  59. $contacts .= ', '.$this->getInput('phone');
  60. }
  61. $data = [
  62. 'name' => $this->getInput('name'),
  63. 'contacts' => $contacts
  64. ];
  65. $response = new CControllerResponseData($data);
  66. $this->setResponse($response);
  67. }
  68. }

Action view

  1. <?php declare(strict_types = 1);
  2. /**
  3. * @var CView $this
  4. */
  5. $this->includeJsFile('example.something.view.js.php');
  6. (new CWidget())
  7. ->setTitle(_('Something view'))
  8. ->addItem(new CDiv($data['name']))
  9. ->addItem(new CPartial('module.example.something.reusable', [
  10. 'contacts' => $data['contacts']
  11. ])
  12. ->show();