20 模块

概述

无需修改Zabbix源代码,即可通过添加第三方模块或开发自定义模块来增强Zabbix前端功能。

请注意模块代码将run与Zabbix源代码相同的权限。这意味着:

  • 第三方模块可能具有危害性。您必须信任所安装的模块;
  • 第三方模块代码中的错误可能导致前端崩溃。若发生此情况,只需从前端移除该模块代码。当您重新加载Zabbix前端时,会看到提示某些模块缺失的通知。前往模块 (位于管理常规模块)并再次点击扫描目录,即可从数据库中移除不存在的模块。

安装

请务必阅读特定模块的安装手册。 建议逐个安装新模块以便轻松捕获故障。

在安装模块前请注意:

  • 确保从可信来源下载模块。 安装有害代码可能导致数据丢失等后果
  • 相同模块的不同版本(相同ID)可以安装在

    parallel, but only a single version can be enabled at once

模块安装步骤:

  • 将模块解压到Zabbix前端modules文件夹内的独立目录中
  • 确保模块目录至少包含manifest.json文件 file
  • 访问模块 并点击扫描目录按钮
  • 新模块将出现在列表中,显示其version、作者、 描述和状态信息
  • 点击状态启用模块

故障排除:

问题 解决方案
模块未出现在列表中 确保Zabbix前端的modules/your-module/目录中存在manifest.json文件file。若存在则表示模块不兼容当前Zabbixversion。若manifest.jsonfile不存在,可能是解压到了错误目录。
前端崩溃 模块代码与当前Zabbixversion或服务器配置不兼容。请delete模块文件并重新加载前端。您将看到某些模块缺失的提示。访问模块再次点击扫描目录以从数据库中移除不存在的模块。
出现关于重复命名空间、ID或操作的错误消息 新模块尝试注册的命名空间、ID或操作已被其他启用模块占用。根据错误提示先禁用冲突模块再启用新模块。
出现技术错误消息 将错误报告给模块开发者。

开发模块

模块采用PHP语言编写。推荐使用模型-视图-控制器(MVC)软件设计模式,这与Zabbix前端架构一致,能简化开发流程。虽然不强制要求,但建议启用PHP严格类型模式。

请注意,通过模块可以轻松为Zabbix前端添加新菜单监控项及对应的视图和操作。但目前无法通过模块注册新的API或create新的数据库表。

模块结构

每个模块都是一个目录(位于modules目录内), 其中包含控制器、视图及其他代码的子目录:

example_module_directory/           (required)
    manifest.json                   (required)  Metadata and action definition.
    Module.php                                  Module initialization and event handling.
    actions/                                    Action controller files.
        SomethingView.php
        SomethingCreate.php
        SomethingDelete.php
        data_export/                                 
            ExportAsXml.php
            ExportAsExcel.php
    views/                                      View files.
        example.something.view.php
        example.something.delete.php
        js/                                     JavaScript files used in views.
            example.something.view.js.php
    partials/                                   View partial files.
        example.something.reusable.php
        js/                                     JavaScript files used in partials.
            example.something.reusable.js.php

如你所见,自定义模块目录中唯一必需的file是 manifest.json。若缺少此file,模块将无法注册。 Module.php负责注册菜单监控项并处理诸如'onBeforeAction' 和'onTerminate'等事件。actionsviewspartials目录包含 模块操作所需的PHP和JavaScript代码。

命名规范

在create模块之前,必须就不同模块监控项(如目录和文件)的命名规范达成一致,以便保持组织有序。您也可以在模块结构章节中找到相关示例。

监控项 命名规则 示例
模块目录 小写字母[a-z]、下划线和数字 example_v2
操作子目录 小写字母[a-z]和下划线字符 data_export
操作文件 驼峰命名法,以操作类型结尾 SomethingView.php
视图和局部文件 小写字母[a-z]
单词间用点号分隔
module.前缀开头后接模块名称
以操作类型和.phpfile扩展名结尾
module.example.something.view.php
Javascript文件 适用与视图和局部文件相同的规则,但扩展名为.js.phpfile。 module.example.something.view.js.php

请注意,对于视图和局部file名称,'模块'前缀和名称包含是强制要求的,除非您需要覆盖Zabbix核心视图或局部文件。但此规则不适用于操作file名称。

清单准备

每个模块都应包含一个manifest.json file文件,其中需以JSON格式声明以下字段:

参数 必填 类型 默认值 描述
manifest_version Double - 模块清单version。当前支持的version为1
id String - 模块ID。同一时间只能启用一个具有相同ID的模块。
name String - 在管理界面显示的模块名称。
version String - 在管理界面显示的模块version。
namespace String - Module.php及动作类使用的PHP命名空间。
author String "" 在管理界面显示的模块作者。
url String "" 在管理界面显示的模块URL。
description String "" 在管理界面显示的模块描述。
actions Object {} 需通过该模块注册的动作。参见Actions章节。
config Object {} 模块配置项。

具体示例可参阅参考章节中的manifest.json范例。

动作

该模块将控制manifest.jsonfile中actionsobject定义的前端操作。通过这种方式定义新操作。同样地,您可以重定义现有操作。actions的每个键应表示操作名称,对应的值应包含class,并可选择性地包含layoutview键。

一个操作由四个部分组成:名称、控制器、视图和布局。数据验证和准备通常在控制器中完成,输出格式化在视图或部分视图中完成,布局负责用菜单、页眉、页脚等元素装饰页面。

模块操作必须在manifest.jsonfile中定义为actionsobject:

参数 必填 类型 默认值 描述
key String - 操作名称,小写字母[a-z],用点分隔单词。
class String - 操作类名,包括actions目录内的子目录路径(如果使用)。
layout String "layout.htmlpage" 操作布局。
view String null 操作视图。

有几种预定义的布局,如layout.jsonlayout.xml。这些适用于产生不同于HTML结果的操作。您可以在app/views/目录中探索预定义的布局,甚至可以create自己的布局。

有时只需要重定义某些操作的视图部分,而保持控制器不变。在这种情况下,只需将必要的视图和/或部分文件放在模块的views目录中。

作为参考,请参阅参考部分中的示例操作控制器file。请不要犹豫探索Zabbix源代码中位于app/目录下的当前操作。

Module.php

这个可选的PHPfile负责模块初始化以及事件处理。类'模块'应在此file中定义,扩展基类\Core\CModule。Module类必须在manifest.jsonfile中指定的命名空间中定义。

<?php

namespace Modules\Example;
use Core\CModule as BaseModule;

class Module extends BaseModule {
    ...
}

作为参考,请参阅参考部分中的Module.php示例。

参考

本节包含前文介绍的不同模块元素的基础版本

manifest.json

{
    "manifest_version": 1.0,
    "id": "example_module",
    "name": "Example module",
    "version": "1.0",
    "namespace": "Example",
    "author": "John Smith",
    "url": "http://module.example.com",
    "description": "Short description of the module.",
    "actions": {
        "example.something.view": {
            "class": "SomethingView",
            "view": "module.example.something.view"
        },
        "example.something.create": {
            "class": "SomethingCreate",
            "layout": null
        },
        "example.something.delete": {
            "class": "SomethingDelete",
            "layout": null
        },
        "example.something.export.xml": {
            "class": "data_export/ExportAsXml",
            "layout": null
        },
        "example.something.export.excel": {
            "class": "data_export/ExportAsExcel",
            "layout": null
        }
    },
    "config": {
        "username": "john_smith"
    }
}

Module.php

<?php declare(strict_types = 1);

namespace Modules\Example;

use APP;
use CController as CAction;

/**
 * Please see Core\CModule class for additional reference.
 */
class Module extends \Core\CModule {

    /**
     * Initialize module.
     */
    public function init(): void {
        // Initialize main menu (CMenu class instance).
        APP::Component()->get('menu.main')
            ->findOrAdd(_('Reports'))
                ->getSubmenu()
                    ->add((new \CMenuItem(_('Example wide report')))
                        ->setAction('example.report.wide.php')
                    )
                    ->add((new \CMenuItem(_('Example narrow report')))
                        ->setAction('example.report.narrow.php')
                    );
    }

    /**
     * Event handler, triggered before executing the action.
     *
     * @param CAction $action  Action instance responsible for current request.
     */
    public function onBeforeAction(CAction $action): void {
    }

    /**
     * Event handler, triggered on application exit.
     *
     * @param CAction $action  Action instance responsible for current request.
     */
    public function onTerminate(CAction $action): void {
    }
}

动作控制器

<?php declare(strict_types = 1);

namespace Modules\Example\Actions;

use CControllerResponseData;
use CControllerResponseFatal;
use CController as CAction;

/**
 * Example module action.
 */
class SomethingView extends CAction {

    /**
     * Initialize action. Method called by Zabbix core.
     *
     * @return void
     */
    public function init(): void {
        /**
         * Disable SID (Session ID) validation. Session ID validation should only be used for actions which involve data
         * modification, such as update or delete actions. In such case Session ID must be presented in the URL, so that
         * the URL would expire as soon as the session expired.
         */
        $this->disableSIDvalidation();
    }

    /**
     * Check and sanitize user input parameters. Method called by Zabbix core. Execution stops if false is returned.
     *
     * @return bool true on success, false on error.
     */
    protected function checkInput(): bool {
        $fields = [
            'name'  => 'required|string',
            'email' => 'required|string',
            'phone' => 'string'
        ];

        // Only validated data will further be available using $this->hasInput() and $this->getInput().
        $ret = $this->validateInput($fields);

        if (!$ret) {
            $this->setResponse(new CControllerResponseFatal());
        }

        return $ret;
    }

    /**
     * Check if the user has permission to execute this action. Method called by Zabbix core.
     * Execution stops if false is returned.
     *
     * @return bool
     */
    protected function checkPermissions(): bool {
        $permit_user_types = [USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN];

        return in_array($this->getUserType(), $permit_user_types);
    }

    /**
     * Prepare the response object for the view. Method called by Zabbix core.
     *
     * @return void
     */
    protected function doAction(): void {
        $contacts = $this->getInput('email');

        if ($this->hasInput('phone')) {
            $contacts .= ', '.$this->getInput('phone');
        }

        $data = [
            'name' => $this->getInput('name'),
            'contacts' => $contacts
        ];

        $response = new CControllerResponseData($data);

        $this->setResponse($response);
    }
}

动作视图

<?php declare(strict_types = 1);

/**
 * @var CView $this
 */

$this->includeJsFile('example.something.view.js.php');

(new CWidget())
    ->setTitle(_('Something view'))
    ->addItem(new CDiv($data['name']))
    ->addItem(new CPartial('module.example.something.reusable', [
        'contacts' => $data['contacts']
    ])
    ->show();