MyException - 我的异常网
当前位置:我的异常网» 综合 » 怎么创建一个zenpack(翻译)

怎么创建一个zenpack(翻译)

www.MyException.Cn  网友分享于:2013-11-07  浏览:28次
如何创建一个zenpack(翻译)

 

如何创建一个zenpack 来添加新属性来扩展device

 

这篇文章你能获取到什么信息

这篇文章解释了如果创建一个zenpack来扩展device 增加 一个componet。如何增加一个新的snmp oid 到zenoss中,如何在gui上看到新的component(其实gui的部分坐着没写完)。

 

一个新的zenpack会包括:

1)一个device的子类

2)一个DeviceComponent的子类(里面包括了新的字段)

3)一个modeler 来获取新的oid 提供给 DeviceComponent

4)一个zope 模板来生成 试图展现在前端页面上(zeoss3.0 使用javascript来写了)

 

背景介绍

 

我已经阅读了zenoss的开发者文档和admin文档,但是任何地方都没发现一段描述创建一个zenpack完整的流程的章节。我搜索了网上能找到的代码,但是没有一个zenpack中的modeler会生成一些新的属性到device里。因为网上能找到的发布的zenpack里都没有扩展device和生成一个modeler。我在zenoos的论坛上找到了一篇名为《 Custom ZenPack Rough Guide》的帖子描述的内容正是我想要的,但是这个帖子唯一的问题是作者仅仅建议修改变量名,类名,和oid。这篇文章的另个问题是它正对的是老版本的zenpack,所以一些类名,包名,必须要修改才能在当前的系统中运行

 

Zenpack的目录结构

Zenpacks 必须有3个python包名来组成,用“.”来分开(例如ZenPacks.test.ZPool) 第一个包名一般都是Zenpack。文件之后会自动生成。

 

 

对于一个名叫Zenpacks.test.ZPool的zenpack来说目录结构一般为

<Zenoss home>/zenoss/ZenPacks/

    ZenPacks.test.ZPool/  <Zenpack root directory>

        ZenPacks.test.ZPool.egg-info

        ZenPacks              <The following directories will reflect the Zenpack name as python packages>

            __init__.py

            test

                __init__.py

                ZPool     <任何model对象都应该放在此目录下>

                    __init__.py

                    daemons

                    datasources

                    lib

                    migrate

                    modeler          <存放modeler module 通过oid来收集一些snmp信息>

                        __init__.py

                        plugins

                            __init__.py

                            ZPoolDeviceDetailsModeler.py   <modeler module(collector)>

                    objects

                    reports

                    skins           <存放视图模板,用在GUI上展示数据>

                        __init__.py

                        ZenPacks.test.ZPool  <name of Zenpack>

                            ZPoolDeviceDetailTemplate.pt

 

Model objects

 

model object 应该被存放在 zenpack名最后一个点后面那个名字的文件夹中。(Zenpack.test.ZPool的话就是在ZPool文件夹)

增加一个component到device中,我们需要做如下事:

1)创建一个继承device的对象(它增加一个新的关系到device中),在这个例子中,我命名它为ZPoolDevice。

2)创建一个对象 继承DeviceComponent和ManagedEntity (里面同时定义了一个新的关系链接到ZPoolDevice),命名为ZPoolComponet。

 

ZPoolDevice 内容

from Globals import InitializeClass
from Products.ZenRelations.RelSchema import *
from Products.ZenModel.Device import Device
from Products.ZenModel.ZenossSecurity import ZEN_VIEW
from copy import deepcopy
class ZPoolDevice(Device):
    "An APC Switched PDU"
    #增加一组关系,将ZPoolChild和ZPoolParent绑定起来,ZPoolParent是component
    _relations = Device._relations + (
        ('ZPoolChild', ToManyCont(ToOne,
            'ZenPacks.test.ZPool.ZPoolComponent', 'ZPoolParent')),
        )
    # add to Device relations the relation to ZPoolComponent
    # The relation is initialized with 5 params, relation name from this side, relation type(ToOne, ToManyCont... etc), component module, and the
    # relation name from the other side of the realtion
    # next we will define a new tab in the Gui which will preview zope template
    factory_type_information = deepcopy(Device.factory_type_information)
    factory_type_information[0]['actions'] += (
            { 'id'              : 'ZPoolChild'  #tab id
            , 'name'            : 'ZPool'      #tab name (appears from the device status tab)
            , 'action'          : 'ZPoolDeviceDetailTemplate'    #the zope template to call when this tab is selected
            , 'permissions'     : (ZEN_VIEW, ) },
            )
    def __init__(self, *args, **kw):
        Device.__init__(self, *args, **kw)
        self.buildRelations()
InitializeClass(ZPoolDevice)   #must initialize class
 

 

 

ZPoolComponent 内容

 

import locale
from Globals import DTMLFile
from Globals import InitializeClass
from Products.ZenUtils.Utils import convToUnits
from Products.ZenRelations.RelSchema import *
from Products.ZenModel.ZenossSecurity import ZEN_VIEW, ZEN_CHANGE_SETTINGS
from Products.ZenModel.DeviceComponent import DeviceComponent
from Products.ZenModel.ManagedEntity import ManagedEntity
from Products.ZenUtils.Utils import prepId
class ZPoolComponent(DeviceComponent, ManagedEntity):
    #define the type (name to be used in zenoss, most probably as a database table name)
    portal_type = meta_type = 'ZPoolComponent'
    zPoolName = ""
    health = ""
    #define component fields
	#新类的属性,zPoolName和health
    _properties = (
        {'id':'zPoolName', 'type':'string', 'mode':''},
        {'id':'health', 'type':'string', 'mode':''}
        )
    #define relation the same as in the Device but only inverted
    _relations = (
        ("ZPoolParent", ToOne(ToManyCont,
            "ZenPacks.test.ZPool.ZPoolDevice", "ZPoolChild")),
        )
    #some getters to be called from the zope template
    def viewName(self):
        return self.zPoolName
    def getZPoolName(self):
               return self.zPoolName
    def isOnline(self):
    #用过modeler收集到的health属性来判断状态
        return self.health == 'ONLINE'
    #return a new 'Relation' object (the object will be populated at runtime)
    def device(self):
        return self.ZPoolParent()
    def getRRDNames(self):
        return []
InitializeClass(ZPoolComponent)
 

Modeler

modeler 的作用是获取snmp结果,然后存储字段信息。它应该存放在<Zenosshome>/ZenPacks.test.ZPool/ZenPacks/test/ZPool/modeler/plugins/下。modeler有2中模式,一种是映射 snmp 表,另一种是映射定义好的oid。在这个例子中我使用第二种方式。

 

在这个modeler中,它的oid是.1.3.6.1.4.1.2021.55.1,是自己定义的snmp脚本,会返回字符串“data1 ONLINE|data2 DEGRADED|rpool ONLINE” 。

 

modeler代码:

from Products.DataCollector.plugins.CollectorPlugin import SnmpPlugin, GetTableMap, GetMap
from Products.DataCollector.plugins.DataMaps import ObjectMap
class ZPoolDeviceDetailsModeler(SnmpPlugin):
    relname = "ZPoolChild"  #The ralation name from the Device side
    modname = "ZenPacks.test.ZPool.ZPoolComponent"   #the module of the component to be populated
    #list of oids to get, and their respective name, here zenoss will call that oid and will call process() with a parameter result containing map ['zPoolHealth': <value returned>]
    snmpGetMap = GetMap({'.1.3.6.1.4.1.2021.55.1' : 'zPoolHealth',
                         })
    #for the case of one to may relation process should return a list of relations mappings relMap
    def process(self, device, results, log):
        """collect snmp information from this device
        @param device: device that is currently modeled
        @param results: tuple of (non snmp table data, snmp table data) both as dict
        @param log: logger"""
        log.info('processing %s for device %s', self.name(), device.id)
        getdata, tabledata = results
        rm = self.relMap()
        zPoolHealth = getdata['zPoolHealth']
        # create a different object model for each relation model and append it to relation model list
        for zPool in zPoolHealth.split('|'):
            om = self.objectMap()
            zpoolFields = zPool.split()
            om.zPoolName = zpoolFields[0]
            om.health = zpoolFields[1]
            rm.append(om)
            om.id = self.prepId(str(om.zPoolName))
            log.info('Health for ZPool %s Collected health is %s'%(om.zPoolName, om.health))
        return rm
 

此时在zenpack的日志里可以看到‘Health for ZPool %s Collected health is %s’,的内容,但是还不能通过GUI看到。(因为作者没有完成GUI部分的代码)

 

其实我觉得翻的还是比较烂的,大家看的不舒服可以看原文。

原文出处:http://georgefakhri.wordpress.com/2009/07/15/how-to-create-a-zenpack/

 

我跟作者开始写这篇文章时的感受一样,在zenoss的开发文档中没有一段比较简单的讲述一个最基本的zenpack的开发流程,它将很多功能拆分开来将, 而且代码也没很详细的解释,大多数都是贴出其中的一段。最后在作者的这篇文章的评论中发现了一份相对详细的zenpack的文档地址:http://community.zenoss.org/docs/DOC-10268,我看完之后我自己对zenpack大致上有了粗略的一些了解。

 

zenpack最基本的开发如上所说的就4部分

1)device文件,用来创建一个对象,链接到device,此例中是ZPoolDevice。

2)component文件,新device的新属性在此文件中定义,GUI中页面的下拉选项也在次定于,还有一些函数用来当调用数据库中对象属性时初始化用(我自己还没找到modeler中获取到的数据存在哪里了,很苦恼)见ZPoolComponent.py

3)modeler 文件及时一个collector,用过snmp来获取数据,用process()方法来解析,处理,存储数据,见ZPoolDeviceDetailModeler.py

4)最后需要一个文件来将获取的数据展示到页面上,在zenoss3之前是用过skin中的。pt文件,是html写的,zenoss3开始通过使用javascript来写。

 

我自己现在将作者这篇没写完的部分写好了,但是一直界面上看不到,很郁闷。国内,即使是国外zenpack的资料实在太少,官方文档也比较烂。。。没啥多说的。很郁闷。

by:pakoo

email:zealzpc@gmial.com

已经写完GUI部分顺利调试通过,过几天写份完整的开发介绍。

 

先附上GUI代码

info.py

__doc__="""info.py

Representation of Bridge components.

$Id: info.py,v 1.2 2010/12/14 20:45:46 jc Exp $"""

__version__ = "$Revision: 1.4 $"[11:-2]

from zope.interface import implements
from Products.Zuul.infos import ProxyProperty
from Products.Zuul.infos.component import ComponentInfo
from Products.Zuul.decorators import info
#from Products.ZenUtils.Utils import convToUnits
from ZenPacks.test.ZPool import interfaces


class ZPoolInterfaceInfo(ComponentInfo):
    implements(interfaces.IBridgeInterfaceInfo)

    zPoolName = ProxyProperty("zPoolName")
    health = ProxyProperty("health")


    @property
    def ZPoolName(self):
        return self._object.getZPoolName()
    @property		
    def health(self):
        return self._object.gethealth()

    @property
    def isOnline(self):
        return self._object.isOnline()

 interfaces.py

__doc__="""interfaces

describes the form field to the user interface.

$Id: interfaces.py,v 1.2 2010/12/14 20:46:34 jc Exp $"""

__version__ = "$Revision: 1.4 $"[11:-2]

from Products.Zuul.interfaces import IComponentInfo
from Products.Zuul.form import schema
from Products.Zuul.utils import ZuulMessageFactory as _t


class IBridgeInterfaceInfo(IComponentInfo):
    """
Info adapter for Bridge Interface component
"""
    zPoolName = schema.Text(title=u"zPoolName", readonly=True, group='Details')
    health = schema.Text(title=u"health", readonly=True, group='Details')

 

configure.zcml

 

<?xml version="1.0" encoding="utf-8"?>
<configure xmlns="http://namespaces.zope.org/zope"
           xmlns:browser="http://namespaces.zope.org/browser"
           xmlns:zcml="http://namespaces.zope.org/zcml">

    <configure zcml:condition="installed Products.Zuul">

        <adapter factory=".info.ZPoolInterfaceInfo"
                 for=".ZPoolComponent.ZPoolComponent"
                 provides=".interfaces.IBridgeInterfaceInfo"
                 />

        <browser:resourceDirectory
                 name="ZPool"
                 directory="resources"
                 />

        <browser:viewlet
                 name="js-ZPool"
                 paths="/++resource++ZPool/ZPool.js"
                 weight="10"
                 manager="Products.ZenUI3.browser.interfaces.IJavaScriptSrcManager"
                 class="Products.ZenUI3.browser.javascript.JavaScriptSrcBundleViewlet"
                 permission="zope2.Public"
                 />
    </configure>
</configure>

 

ZPool.js

(function(){

var ZC = Ext.ns('Zenoss.component');


function render_link(ob) {
    if (ob && ob.uid) {
        return Zenoss.render.link(ob.uid);
    } else {
        return ob;
    }
}

ZC.ZPoolInterfacePanel = Ext.extend(ZC.ComponentGridPanel, {
    constructor: function(config) {
        config = Ext.applyIf(config||{}, {
            componentType: 'ZPool',
            fields: [
                {name: 'zPoolName'},
                {name: 'health'},
                {name: 'uid'},
                {name: 'name'},
                {name: 'severity'},
                {name: 'status'},
                {name: 'hasMonitor'},
                {name: 'monitor'},
            ],
            columns: [
			{
                id: 'severity',
                dataIndex: 'severity',
                header: _t('Events'),
                renderer: Zenoss.render.severity,
                width: 60
            },
			{
                id: 'zPoolName',
                dataIndex: 'zPoolName',
                header: _t('zPoolName'),
                sortable: true
            },{
                id: 'health',
                dataIndex: 'health',
                header: _t('health'),
                sortable: true,
            },
			{
                id: 'name',
                dataIndex: 'name',
                header: _t('Name'),
                width: 120,
                sortable: true
            },{
				id: 'monitored',
				dataIndex: 'monitored',
				header: _t('Monitored'),
				width: 60
			}]
        });
        ZC.ZPoolInterfacePanel.superclass.constructor.call(this, config);
    }
});

Ext.reg('ZPoolComponent', ZC.ZPoolInterfacePanel);
ZC.registerName('ZPoolComponent', _t('ZPool Component'), _t('ZPool Component'));
})();

 

文章评论

看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
程序员和编码员之间的区别
程序员和编码员之间的区别
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
编程语言是女人
编程语言是女人
为什么程序员都是夜猫子
为什么程序员都是夜猫子
Java程序员必看电影
Java程序员必看电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
老程序员的下场
老程序员的下场
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
旅行,写作,编程
旅行,写作,编程
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
10个调试和排错的小建议
10个调试和排错的小建议
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
我的丈夫是个程序员
我的丈夫是个程序员
代码女神横空出世
代码女神横空出世
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
总结2014中国互联网十大段子
总结2014中国互联网十大段子
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
每天工作4小时的程序员
每天工作4小时的程序员
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
鲜为人知的编程真相
鲜为人知的编程真相
如何成为一名黑客
如何成为一名黑客
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员应该关注的一些事儿
程序员应该关注的一些事儿
漫画:程序员的工作
漫画:程序员的工作
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
 程序员的样子
程序员的样子
我是如何打败拖延症的
我是如何打败拖延症的
一个程序员的时间管理
一个程序员的时间管理
那些争议最大的编程观点
那些争议最大的编程观点
中美印日四国程序员比较
中美印日四国程序员比较
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序员都该阅读的书
程序员都该阅读的书
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员的鄙视链
程序员的鄙视链
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有