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:

//     16×16 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: 'p_w_picpaths/example.png',

iconSvg: 'p_w_picpaths/example.svg'});

注:test:_()这里面的内容能跟随页面自动翻译成各国语言

3.node的主视图(workspace)

从workspace类派生,创建Settings.jsExt.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脚本

exampleset -e. /etc/default/openmediavault

. /usr/share/openmediavault/scripts/helper-functions

OMV_EXAMPLE_XPATH="/config/services/example"OMV_EXAMPLE_CONF="/tmp/example.conf"

cat < ${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/