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

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

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