Browse files

Initial commit by nyeates publishing script; Code was supplied only f…

…rom .egg; May be missing
  • Loading branch information...
0 parents commit a5b9eaecbe7f1c1dc1de6c486e1180807b41ec47 Nick Yeates committed Nov 21, 2011
9 .gitignore
@@ -0,0 +1,9 @@
@@ -0,0 +1,8 @@
+# This graft causes all files located under the ZenPacks/ subdirectory to be
+# included in the built ZenPack .egg. Files located in the top-level directory
+# of the ZenPack will not be explicitly included.
+# You can read more about the format and available options available in this
+# file at the following URL.
+graft ZenPacks
172 README.markdown
@@ -0,0 +1,172 @@
+This file should contain documentation that is specific to what your ZenPack does.
+It should give example screenshots, explain how to install it, amongst other topics.
+Please see for details.
+This file was automatically pulled from
+It contains general comments, not specific to this ZenPack
+# ZenPack Template
+This README describes the structure of the ZenPack template that gets
+automatically created by Zenoss when you add a ZenPack through the web
+## Files
+At the top-level a ZenPack must have a Almost always a
+file should exist, and in cases where external dependencies must be built for
+inclusion in the ZenPack, a GNUmakefile. Examples of these files with inline
+comments are included in this template.
+Also included in the ZenPackTemplate is a configure.zcml. As more of Zenoss'
+extensibility moves to using ZCA (Zope Component Architecture) this file
+becomes crucial to hooking into various aspects of Zenoss.
+## Files and Subdirectories
+The following sections describe the purpose and use for each of the default
+subdirectories. Note that if the described functionality is not of use in your
+ZenPack it is safe to remove any of the default directories.
+### src/
+The src/ top-level directory in ZenPacks is the conventional place to add
+third-party dependencies to your ZenPack. It should only be used as a staging
+area to do any build work necessary for the dependency.
+See GNUmakefile (or GNUmakefile.example) for examples of how to have
+your third-party dependencies automatically compiled and installed at the right
+time and into the right location.
+The following sections describe the directories contained within the
+namespaced ZenPacks/NAMESPACE/PACKNAME/ subdirectories.
+#### bin/
+Any general tools delivered by your ZenPack that would be used by the Zenoss
+administrator at the command line should go into this directory by convention.
+When the ZenPack is installed all files in this directory will be made
+#### browser/
+The browser subdirectory should contain all code and configuration that's
+specific to the Zenoss web interface. The provided configure.zcml will
+automatically load the example browser/configure.zcml and register the
+browser/resources/ subdirectory to serve static web content.
+#### daemons/
+All files in the daemons/ subdirectory get special handling. Upon installing
+the ZenPack, the following actions will occur.
+ 1. The file will be made executable (chmod 0755)
+ 2. A symlink to the file will be created in $ZENHOME/bin/
+ 3. An configuration file will be generated at $ZENHOME/etc/DAEMON_NAME.conf
+Assuming that you don't have a $ZENHOME/etc/DAEMONS_TXT_ONLY file this daemon
+will also become part of the normal zenoss start and stop processes.
+You can find an example daemon control script in daemons/zenexample. For most
+purposes this file can be renamed to the name of the daemon you want to create
+and modified to change the DAEMON_NAME. No other modifications are typically
+needed. Note that this example control script does expect to launch the real
+daemon code which should be located at ../
+#### datasources/
+Any new datasource types you want to add must be added as classes into the
+datasources/ subdirectory. When Zenoss is building the list of available
+datasources it will scan the datasources/ subdirectory for all installed
+An example datasource at datasources/
+#### lib/
+The lib/ directory should be the installation target for any third-party
+libraries that are built by the GNUmakefile. It can also be used as the
+conventional location to drop Python-only libraries that don't require
+any compilation or special installation.
+#### libexec/
+Any scripts executed by COMMAND datasources in your ZenPack go in this
+directory by convention. When the ZenPack is installed all files in this
+directory will be made executable.
+#### migrate/
+ZenPacks can include migrate scripts that allow you to run custom code to
+handle any tasks that are needed to upgrade your ZenPack from one version to
+another. All .py files in this migrate/ subdirectory will be evaluated when the
+ZenPack is installed.
+You can find an example migrate script at migrate/
+#### modeler/
+Any modeler plugins distributed with your ZenPack must be located under the
+plugins/ subdirectory. The directory structure and filenames under plugins/
+map directly to the plugins' name in the user interface. For example, if you
+wanted to create a modeler plugin called "community.snmp.ExampleMap" you would
+create the following directory structure.
+It is recommended that the first portion of the namespace be a short lowercase
+form of your name, or organization's name. Alternatively you can choose to use
+"community" if you plan to publish the ZenPack and are open to outside
+contributions. Zenoss, Inc. will always use "zenoss." The second portion of the
+namespace can be the protocol that is used to collect the data. If you are not
+using a common protocol it is acceptable to skip the second portion of the
+namespace and have something like "community.MongoDB" instead.
+ plugins/
+ community/
+ snmp/
+Note that the `````` files must exist and should be empty files. Otherwise
+your modeler plugins won't be imported and usable within Zenoss.
+#### objects/
+All .xml files in this objects/ directory will be loaded into the object
+database when the ZenPack installs. All of the objects defined in the XML files
+will be automatically associated with the ZenPack.
+When you export the ZenPack from the user interface all objects associated with
+the ZenPack will be exported into a file called "objects.xml" specifically. For
+this reason it is recommended to let Zenoss manage the objects.xml file and to
+never manually create or modify any .xml files in this directory unless you
+know what you're doing.
+When a ZenPack is removed, any objects associated with the ZenPack will be
+recursively removed from Zenoss. For example, if you associated the /Server
+device class with your ZenPack and removed the ZenPack, the /Server device
+class, and all devices within it would also be deleted.
+When a ZenPack is upgraded, or re-installed on top of itself, all objects in
+the XML files are overlaid on the existing object database. This results in a
+merge of the existing objects and what are defined in the XML files with the
+XML file properties and relationships winning any conflicts.
+#### reports/
+Custom reports will be loaded from this directory when the ZenPack is
+installed. Subdirectories (with the exception of plugins/) will be mapped
+directly to the report folders in the web interface. So if you add a .rpt file
+into a subdirectory named "Performance Reports" you will find your report in
+the Performance Reports folder in the web interface after installing the
+The plugins/ subdirectory should include any Python plugins your custom reports
+call. So if your .rpt file contains a line such as the following..
+objects python:here.ReportServer.plugin('myplugin', tableState);
+There should be a corresponding file in the plugins/ subdirectory.
+You can find an example report at Example Reports/Example Report.rpt.example
+that uses a plugin which can be found at plugins/
+#### services/
+ZenHub services will be loaded from the services/ directory. These services
+run inside the zenhub daemon and are responsible from all interaction with
+collector daemons.
+You can find an example service at services/
+#### tests/
+All unit tests for your ZenPack should live in this directory. You can find an
+example test suite at tests/
66 ZenPacks/ShaneScott/DeviceSearch/
@@ -0,0 +1,66 @@
+import logging
+log = logging.getLogger('zen.DeviceSearch')
+import os
+import Globals
+from Products.CMFCore.DirectoryView import registerDirectory
+skinsDir = os.path.join(os.path.dirname(__file__), 'skins')
+if os.path.isdir(skinsDir):
+ registerDirectory(skinsDir, globals())
+from Products.ZenModel.ZenPack import ZenPack as ZenPackBase
+class ZenPack(ZenPackBase):
+ def install(self, dmd):
+ super(ZenPack, self).install(dmd)
+ def remove(self, dmd, leaveObjects=False):
+ super(ZenPack, self).remove(dmd, leaveObjects)
+from Products.ZenUtils.Utils import monkeypatch
+ from Products.Zuul.catalog.global_catalog import DeviceWrapper, IpInterfaceWrapper
+ @monkeypatch('Products.Zuul.catalog.global_catalog.DeviceWrapper')
+ def searchKeywords(self):
+ device = self._context.primaryAq()
+ return super(DeviceWrapper, self).searchKeywords() + (device.zSnmpCommunity,)
+ # ^ Add other indexable properties (cProp, zProp, Attr) here as context device
+ @monkeypatch('Products.Zuul.catalog.global_catalog.IpInterfaceWrapper')
+ def searchKeywordsForChildren(self):
+ """
+ When searching, what things to search on
+ """
+ if self._context.titleOrId() in ('lo', 'sit0'):
+ # ^ Add other interface names which are ignored from indexing
+ return ()
+ try:
+ # If we find an interface IP address, link it to an interface
+ ipAddresses = [x for x in self._context.getIpAddresses() \
+ if not x.startswith('') and \
+ not x.startswith('::1/')]
+ except Exception:
+ ipAddresses = []
+ return super(IpInterfaceWrapper, self).searchKeywordsForChildren() + (
+ self._context.description, self._context.titleOrId(),
+ # ^ Add other indexable properties (cProp, zProp, Attr) here as context self._context
+ )
+ @monkeypatch('Products.Zuul.catalog.global_catalog.IpInterfaceWrapper')
+ def searchExcerpt(self):
+ """
+ How the results are displayed in the search drop-down
+ """
+ return super(IpInterfaceWrapper, self).searchExcerpt() + ' ' + ' '.join([
+ self._context.description, self._context.titleOrId(),
+ ])
+ # ^ Add other indexable properties (cProp, zProp, Attr) here as context self._context
+except ImportError:
+ pass
7 ZenPacks/ShaneScott/DeviceSearch/configure.zcml
@@ -0,0 +1,7 @@
+<configure xmlns=""
+ xmlns:five=""
+ xmlns:browser="">
+ <include package=".device"/>
0 ZenPacks/ShaneScott/DeviceSearch/device/
No changes.
104 ZenPacks/ShaneScott/DeviceSearch/device/
@@ -0,0 +1,104 @@
+##Modified copy of zenoss DeviceSearch
+from zope.component import adapts
+from zope.interface import implements
+from Products.AdvancedQuery import MatchGlob, And, Or, Eq, In, RankByQueries_Max
+from Products.ZCatalog.interfaces import ICatalogBrain
+from Products.ZenModel.DataRoot import DataRoot
+from Products.Zuul.utils import allowedRolesAndGroups
+from import ISearchProvider
+from import ISearchResult
+class DeviceSearchProvider(object):
+ """
+ Provider which searches Zenoss's global catalog for matching devices
+ """
+ implements(ISearchProvider)
+ adapts(DataRoot)
+ def __init__(self, dmd):
+ self._dmd = dmd
+ def getSearchResults(self, parsedQuery,
+ sorter=None, unrestricted=False):
+ """
+ Queries the catalog. Searches the searchKeywords index
+ using *keyword1* AND *keyword2* AND so on.
+ If there are preferred categories, find maxResults # of instances
+ before searching other categories.
+ @rtype generator of BrainSearchResult objects
+ """
+ operators = parsedQuery.operators
+ keywords = parsedQuery.keywords
+ if not keywords:
+ return
+ results = self.doMySearch( keywords, unrestricted )
+ if sorter is not None:
+ results = sorter.limitSort(results)
+ return results
+ def doMySearch( self, keywords, unrestricted=False ):
+ def listMatchGlob(op, index, list):
+ return op(*[ MatchGlob(index, '*%s*' % i ) for i in list ])
+ full_query = listMatchGlob(And, 'searchKeywords', keywords)
+ querySet = full_query
+ if not unrestricted:
+ # take permissions into account
+ roles = In('allowedRolesAndUsers', allowedRolesAndGroups(self._dmd))
+ querySet = [full_query, roles]
+ querySet = And(*querySet)
+ catalogItems = self._dmd.global_catalog.evalAdvancedQuery(querySet)
+ brainResults = [DeviceSearchResult(catalogItem)
+ for catalogItem in catalogItems
+ if catalogItem.searchExcerpt is not None]
+ return brainResults
+ def getQuickSearchResults(self, parsedQuery, maxResults=None):
+ """
+ Currently just calls getSearchResults
+ """
+ return self.getSearchResults( parsedQuery, maxResults )
+class DeviceSearchResult(object):
+ """
+ Wraps a brain from the search catalog for inclusion in search results.
+ """
+ implements(ISearchResult)
+ def __init__(self, brain):
+ self._brain = brain
+ @property
+ def url(self):
+ return self._brain.getPath()
+ @property
+ def category(self):
+ return self._brain.meta_type
+ @property
+ def excerpt(self):
+ return self._brain.searchExcerpt
+ iconTemplate = '<img src="%s"/>'
+ @property
+ def icon(self):
+ return self.iconTemplate % self._brain.searchIcon
+ @property
+ def popout(self):
+ return False
8 ZenPacks/ShaneScott/DeviceSearch/device/configure.zcml
@@ -0,0 +1,8 @@
+<configure xmlns="">
+ <subscriber provides=""
+ for="Products.ZenModel.DataRoot.DataRoot"
+ factory=".adapters.DeviceSearchProvider"
+ />
1 ZenPacks/ShaneScott/
@@ -0,0 +1 @@
1 ZenPacks/
@@ -0,0 +1 @@

0 comments on commit a5b9eae

Please sign in to comment.