1
2
3
4
5
6
7
8
9
10
11
12
13
14 """
15 Load modeling and monitoring plugins from standard locations and from
16 ZenPacks. Most of the entry into this module is via the three functions
17 defined at the very bottom of the file. Those functions use the singleton
18 PluginManager objects to load the plugins.
19
20 Classes -
21 PluginImportError - an exception type
22 PluginLoader - jellyable object that has all the information neccessary
23 to dynamically import the plugin module and instantiate the
24 class that shares the module's name
25 CoreImporter - jellyable object that is injected into a PluginLoader.
26 handles importing of plugins found inside Products
27 PackImporter - same as above but for zenpack plugins
28 BaseLoaderFactory - base class for the two loader factories
29 CoreLoaderFactory - generates the PluginLoaders for core plugins
30 PackLoaderFactory - generates the PluginLoaders for zenpack plugins
31 PluginManager - there is one singleton instance of this class for modeling
32 plugins and another for monitoring plugins
33
34 Note that modPath uses a different convention for core versus zenpack plugins.
35
36 core: zenoss.cmd.uname
37 zenpack: ZenPacks.zenoss.AixMonitor.modeler.plugins.zenoss.cmd.uname
38
39 """
40
41 from Products.ZenUtils.Utils import importClass, zenPath
42 import sys
43 import os
44 import exceptions
45 import imp
46 from twisted.spread import pb
47 import logging
48 log = logging.getLogger('zen.Plugins')
49
51 """
52 Capture extra data from plugin exceptions
53 """
54
55 - def __init__(self, plugin='', traceback='' ):
56 """
57 Initializer
58
59 @param plugin: plugin name
60 @type plugin: string
61 @param traceback: traceback from an exception
62 @type traceback: traceback object
63 """
64 self.plugin = plugin
65 self.traceback = traceback
66
67 self.args = traceback
68
70 """
71 Class to load plugins
72 """
73
74 - def __init__(self, package, modPath, lastModName, importer):
75 """
76 package - '/'-separated absolute path to the root of the plugins
77 modules
78 modPath - '.'-spearated module path. for core plugins, it is rooted
79 at the package. for zenpack plugins, it starts with
80 'ZenPacks'
81 lastModName - name of the last module in modPath that is not part of
82 of the plugin name
83 importer - object with an importPlugin method used to import the
84 plugin. the implementation of the import method differs
85 between core and zenpack plugins
86 """
87 self.package = package
88 self.modPath = modPath
89 self.pluginName = modPath.split(lastModName + '.')[-1]
90 self.importer = importer
91
93 """
94 Load and compile the code contained in the given plugin
95 """
96 try:
97 try:
98
99
100 sys.path.insert(0, self.package)
101 pluginClass = self.importer.importPlugin(self.package,
102 self.modPath)
103 return pluginClass()
104 except (SystemExit, KeyboardInterrupt):
105 raise
106 except:
107 import traceback
108 log.debug(traceback.format_exc())
109 raise PluginImportError(
110 plugin=self.modPath, traceback=traceback.format_exc() )
111 finally:
112 try:
113 sys.path.remove(self.package)
114 except ValueError:
115
116 pass
117
118 pb.setUnjellyableForClass(PluginLoader, PluginLoader)
119
121 "generates modPath strings for the modules in a core directory"
122 for absolutePath, dirname, filenames in walker.walk(package):
123 if absolutePath == package:
124 modPathBase = []
125 elif absolutePath.startswith(package):
126 modPathBase = absolutePath[len(package)+1:].split(os.path.sep)
127 else:
128 log.debug('absolutePath must start with package: '
129 'absolutePath=%s, package=%s', absolutePath, package)
130 continue
131 for filename in filenames:
132 if filename.endswith(".py") \
133 and filename[0] not in ('.', "_") \
134 and '#' not in filename \
135 and filename not in ('CollectorPlugin.py', 'DataMaps.py'):
136 yield '.'.join(modPathBase + [filename[:-3]])
137
139
140 - def walk(self, package):
141 return os.walk(package)
142
144
146
147
148
149 plugin_pkg = imp.find_module('.', [package])
150 imp.load_module(package, *plugin_pkg)
151
152
153
154
155
156 clsname = modPath.split('.')[-1]
157 mod = __import__(package + '.' + modPath,
158 globals(),
159 locals(),
160 [clsname])
161
162 return getattr(mod, clsname)
163
164 pb.setUnjellyableForClass(CoreImporter, CoreImporter)
165
172
173 pb.setUnjellyableForClass(PackImporter, PackImporter)
174
183
188
190
191 - def __init__(self, walker, modPathPrefix):
194
196 packModPath = '%s.%s' % (self.modPathPrefix, coreModPath)
197 return PluginLoader(package, packModPath, lastModName, PackImporter())
198
200 """
201 Manages plugin modules. Finds plugins and returns PluginLoader instances.
202 Keeps a cache of previously loaded plugins.
203 """
204
205 - def __init__(self, lastModName, packPath, productsPaths):
206 """
207 Adds PluginLoaders for plugins in productsPaths to the pluginLoaders
208 dictionary.
209
210 lastModName - the directory name where the plugins are found. this name
211 is appended to the following paths
212 packPath - path to the directory that holds the plugin modules inside
213 a zenpack. this path is relative to the zenpack root
214 productsPaths - list of paths to directories that hold plugin
215 modules. these paths are relative to $ZENHOME/Products
216
217 a 'path', as used here, is a tuple of directory names
218 """
219 self.pluginLoaders = {}
220 self.loadedZenpacks = []
221 self.lastModName = lastModName
222 self.packPath = packPath
223 for path in productsPaths:
224 package = zenPath(*('Products',) + path + (lastModName,))
225 self._addPluginLoaders(CoreLoaderFactory(OsWalker()), package)
226
228 """
229 Get the PluginLoader for a specific plugin.
230
231 packs - list of installed zenpacks (ZenPack instances)
232 modPath - the module path of the plugin
233 """
234 if modPath not in self.pluginLoaders:
235 self.getPluginLoaders(packs)
236 if modPath in self.pluginLoaders:
237 return self.pluginLoaders[modPath]
238
240 """
241 Add the PluginLoaders for the packs to the pluginLoaders dictionary.
242 Return the values of that dictionary.
243
244 packs - list of installed zenpacks (ZenPack instances)
245 """
246 try:
247 for pack in packs:
248 if pack.moduleName() not in self.loadedZenpacks:
249 self.loadedZenpacks.append(pack.moduleName())
250 modPathPrefix = '.'.join((pack.moduleName(),) +
251 self.packPath + (self.lastModName,))
252 factory = PackLoaderFactory(OsWalker(), modPathPrefix)
253 package = pack.path(*self.packPath + (self.lastModName,))
254 self._addPluginLoaders(factory, package)
255 except:
256 log.error('Could not load plugins from ZenPacks.'
257 ' One of the ZenPacks is missing or broken.')
258 import traceback
259 log.debug(traceback.format_exc())
260 return self.pluginLoaders.values()
261
263 log.debug("Loading collector plugins from: %s", package)
264 try:
265 loaders = loaderFactory.genLoaders(package, self.lastModName)
266 for loader in loaders:
267 self.pluginLoaders[loader.modPath] = loader
268 except:
269 log.error('Could not load plugins from %s', package)
270 import traceback
271 log.debug(traceback.format_exc())
272
274 """
275 this class is not intended to be instantiated. instead it is a place to
276 hold a singleton instance of PluginManager without having them call the
277 constructor when this module is imported.
278 """
279
280 instance = None
281
282 @classmethod
284 if cls.instance is None:
285 cls.instance = PluginManager(
286 lastModName='plugins',
287 packPath=('modeler',),
288 productsPaths=[('DataCollector',),
289 ('ZenWin', 'modeler',)])
290 return cls.instance
291
293 """
294 this class is not intended to be instantiated. instead it is a place to
295 hold a singleton instance of PluginManager without having them call the
296 constructor when this module is imported.
297 """
298
299 instance = None
300
301 @classmethod
309
312
316
320
325