openmediavault 插件开发
OpenMediaVault,简称omv,是一个开源的基于Debian Linux的下一代网络附加存储(NAS)解决方案。它包含众多服务,如SSH,(S)FTP,SMB / CIFS,DAAP媒体服务器,RSync,BitTorrent客户机等。 并具有通过插件可增强的模块化设计框架特性。
OMV的插件开发,由三个部分组成
- GUI
- 配置文件与RPC
- 模块与shell脚本
GUI(web界面)
后台自动扫描以下目录及其子目录
/var/www/openmediavault/js/omv/module/admin/ /var/www/openmediavault/js/omv/module/user/ /var/www/openmediavault/js/omv/module/public/
1.在service目录下新加一个目录example
/var/www/openmediavault/js/omv/module/admin/service/example
2.新增一个node(左侧导航栏的一个tree对象),创建/var/www/openmediavault/js/omv/module/admin/service/example/EXample.js
// Register a node in the navigation tree. // // id: // Set the ID of the node. // path: // Parent path in the navigation view. // Text: // Service name/title. This is displayed in the navigation. // icon16: // 16x16 pixel icon that is displayed in the navigation tree. // iconSvg: // SVG icon that is displayed in the navigation view. OMV.WorkspaceManager.registerNode({ id: ‘example‘, path: ‘/service‘, text: _(‘Example‘), icon16: ‘images/example.png‘, iconSvg: ‘images/example.svg‘});
注:test:_()这里面的内容能跟随页面自动翻译成各国语言
3.node的主视图(workspace)
从workspace类派生,创建Settings.js
Ext.define(‘OMV.module.admin.service.example.Settings‘, { extend: ‘OMV.workspace.form.Panel‘, // This path tells which RPC module and methods this panel will call to get // and fetch its form values. rpcService: ‘Example‘, rpcGetMethod: ‘getSettings‘, rpcSetMethod: ‘setSettings‘, // getFormItems is a method which is automatically called in the // instantiation of the panel. This method returns all fields for // the panel. getFormItems: function() { return [{ // xtype defines the type of this entry. Some different types // is: fieldset, checkbox, textfield and numberfield. xtype: ‘fieldset‘, title: _(‘General‘), fieldDefaults: { labelSeparator: ‘‘ }, // The items array contains items inside the fieldset xtype. items: [{ xtype: ‘checkbox‘, // The name option is sent together with is value to RPC // and is also used when fetching from the RPC. name: ‘enable‘, fieldLabel: _(‘Enable‘), // checked sets the default value of a checkbox. checked: false }, { xtype: ‘numberfield‘, name: ‘max_value‘, fieldLabel: _(‘Max value‘), minValue: 0, maxValue: 100, allowDecimals: false, allowBlank: true }] }]; } }); // Register a panel into the GUI. // // path: // We want to add the panel in our example node. // The node was configured with the path /service and the id example. // The path is therefore /service/example.//// className: // The panel which should be registered and added (refers to // the class name). OMV.WorkspaceManager.registerPanel({ id: ‘settings‘, path: ‘/service/example‘, text: _(‘Settings‘), position: 10, className: ‘OMV.module.admin.service.example.Settings‘});
注:定义了rpc,此时在页面刷新会报错。“RPC service not found (name=Example)”,此时需要添加rpc文件/usr/share/openmediavault/engined/rpc/example.inc,内容见第二部分
配置文件config.xml和RPC
Config.xml
/etc/openmediavault/config.xml储存了插件设置项,可以在制作debian包时,写在postinst脚本里
#!/bin/shset -e . /etc/default/openmediavault . /usr/share/openmediavault/scripts/helper-functions case "$1" in configure) SERVICE_XPATH_NAME="example" SERVICE_XPATH="/config/services/${SERVICE_XPATH_NAME}" # Add the default configuration if ! omv_config_exists "${SERVICE_XPATH}"; then omv_config_add_element "/config/services" "${SERVICE_XPATH_NAME}" omv_config_add_element "${SERVICE_XPATH}" "enable" "0" omv_config_add_element "${SERVICE_XPATH}" "max_value" "0" fi # Activate package triggers. These triggers are only set during the # package installation. dpkg-trigger update-fixperms dpkg-trigger update-locale ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument" >&2 exit 1 ;;esac #DEBHELPER# exit 0
The RPC = Remote Procedure Call
RPC文件存储在/usr/share/openmediavault/engined/rpc目录下,inc结尾的php文件,rpc文件连接了web GUI和config.xml,使得界面可以控制config文件
example.inc
<?php require_once ‘openmediavault/config.inc‘; require_once ‘openmediavault/error.inc‘; require_once ‘openmediavault/notify.inc‘; require_once ‘openmediavault/rpcservice.inc‘; class OMVRpcServiceExample extends OMVRpcServiceAbstract{ /** * The main event message path. * * @var string */ private $eventMessagePath = ‘org.openmediavault.services.example‘; /** * Get the base XPath of the service. This is a helper function to avoid * "magic numbers". * * @return string */ private function getXpath() { return ‘/config/services/example‘; } /** * Get the name of the RPC service. * * @return string */ public function getName() { return ‘Example‘; } /** * Initialize the RPC service. The RPC methods are registered in this * function with $this->registerMethod. * * @return void */ public function initialize() { $this->registerMethod(‘getSettings‘); $this->registerMethod(‘setSettings‘); } public function getSettings($params, $context) { // $xmlConfig is needed when reading and writing from the configuration. global $xmlConfig; // Validate the RPC caller context. // // validateMethodContext takes the currentcontext as the first // parameter. The second paramter is the valid context and that can be // OMV_ROLE_ADMINISTRATOR, OMV_ROLE_USER or OMV_ROLE_EVERYONE. // This is used to make sure that the right user accesses the method. $this->validateMethodContext($context, [‘role‘ => OMV_ROLE_ADMINISTRATOR]); // Get the configuration object. $object = $xmlConfig->get($this->getXpath()); // If no data was found, throw an exception and provide the XPath that // failed. if (is_null($object)) { throw new OMVException( OMVErrorMsg::E_CONFIG_GET_OBJECT_FAILED, $this->getXpath() ); } // Modify the result data. // boolval and intval converts strings and numbers to their boolean // and integer value. $object[‘enable‘] = boolval($object[‘enable‘]); $object[‘max_value‘] = intval($object[‘max_value‘]); return $object; } public function setSettings($params, $context) { global $xmlConfig; $this->validateMethodContext($context, array( "role" => OMV_ROLE_ADMINISTRATOR )); // Validate the parameters of the RPC service method. // // OpenMediavault uses JSON Schema to validate parameters. A more // detailed specification is provided here http://json-schema.org/ $this->validateMethodParams( $params, ‘{ "type": "object", "properties": { "enable": { "type": "boolean" }, "max_value":{ "type": "integer", "minimum": 1, "maximum": 100 } } }‘ ); // Update the configuration object. $object = [ ‘enable‘ => boolval($params[‘enable‘]), ‘max_value‘ => $params[‘max_value‘], ]; // Update the configuration file. If it fails it throws an exception. if ($xmlConfig->replace($this->getXpath(), $object) === false) { throw new OMVException( OMVErrorMsg::E_CONFIG_SET_OBJECT_FAILED, $this->getXpath() ); } // Notify configuration changes. // // This will notify event listeners such as the service module // to perform certain tasks. The most common one is to mark the // service as dirty. $dispatcher = &OMVNotifyDispatcher::getInstance(); $dispatcher->notify(OMV_NOTIFY_MODIFY, $this->eventMessagePath, $object); return $object; } } // Register the RPC service. $rpcServiceMgr = &OMVRpcServiceMgr::getInstance(); $rpcServiceMgr->registerService(new OMVRpcServiceExample());
模块与shell脚本
module
RPC用来实现界面修改和获取配置文件,模块用来监控和使其修改生效。模块目录在/usr/share/openmediavault/engined/module
Example.inc
<?php require_once ‘openmediavault/config.inc‘; require_once ‘openmediavault/error.inc‘; require_once ‘openmediavault/initscript.inc‘; require_once ‘openmediavault/module.inc‘; class OMVModuleExample extends OMVModuleServiceAbstract implements OMVINotifyListener, OMVIModuleServiceStatus{ /** * The main event message path. * * @var string */ private $eventMessagePath = ‘org.openmediavault.services.example‘; } /** * Get the base XPath of the service. This is a helper function to avoid * "magic numbers". * * @return string */ private function getXpath() { return ‘/config/services/example‘; } /** * Get the module name. * * @return string */ public function getName() { return ‘example‘; } /** * Get the module status. * * @return array * * @throws OMVException */ public function getStatus() { global $xmlConfig; // Get the configuration object. $object = $xmlConfig->get($this->getXpath()); if (is_null($object)) { throw new OMVException( OMVErrorMsg::E_CONFIG_GET_OBJECT_FAILED, $this->getXpath() ); } // Return the status of the service. This information is displayed // under Diagnostics/Services. return array( ‘name‘ => $this->getName(), ‘title‘ => gettext(‘Example‘), ‘enabled‘ => boolval($object[‘enable‘]), ‘running‘ => false ); } /** * Generate the configuration. * * @return void * * @throws OMVException */ public function applyConfig() { global $xmlConfig; $cmd = sprintf(‘export LANG=C; omv-mkconf %s 2>&1‘, $this->getName()); if (0 !== $this->exec($cmd, $output)) { throw new OMVException( OMVErrorMsg::E_EXEC_FAILED, $cmd, implode(PHP_EOL, $output) ); } } /** * Bind listeners. * * @param OMVNotifyDispatcher $dispatcher * @return void */ public function bindListeners(OMVNotifyDispatcher $dispatcher) { $moduleMgr = &OMVModuleMgr::getInstance(); // Add listeners here. The most common thing is to monitor configuration // changes on the service. When the config is changed the module // sets itself as dirty (as seen below). Setting a module as dirty // makes the apply button appear in the web interface (which in turn // calls the applyConfig function on each module with a dirty state). $dispatcher->addListener( OMV_NOTIFY_MODIFY, $this->eventMessagePath, [$this, ‘setDirty‘] ); } } // Register the module. $moduleMgr = &OMVModuleMgr::getInstance(); $moduleMgr->registerModule(new OMVModuleExample());
注:模块注册了notify,rpc在修改配置文件后会通知notify文件为dirty状态,从而在页面触发apply change提示。
Shell脚本生成配置文件
在module中的applyconfig函数中,执行了omv-mkconf example命令,该命令调用了/usr/share/openmediavault/mkconf/example脚本
example
set -e. /etc/default/openmediavault . /usr/share/openmediavault/scripts/helper-functions OMV_EXAMPLE_XPATH="/config/services/example"OMV_EXAMPLE_CONF="/tmp/example.conf" cat <<EOF > ${OMV_EXAMPLE_CONF}enable = $(omv_config_get "${OMV_EXAMPLE_XPATH}/enable") max_value = $(omv_config_get "${OMV_EXAMPLE_XPATH}/max_value") EOF exit 0
注:需要755权限,执行完该脚本将会生成/tmp/example.conf文件。
至此,一个openmediavault的简单插件源码已经制作完成,接下来只需要制作包就可以啦。
refer:https://forum.openmediavault.org/index.php/Thread/5600-DIY-Plugin-Development/