1
2
3
4
5
6
7
8
9
10
11
12
13 __doc__ = "Manage ZenPacks"
14
15 import os, sys
16 import logging
17 import ConfigParser
18 from zipfile import ZipFile
19 from StringIO import StringIO
20
21 import Globals
22 import transaction
23 from ZODB.POSException import ConflictError
24
25 from Products.ZenModel.ZenPack import ZenPack, ZenPackException
26 from Products.ZenModel.ZenPack import ZenPackNeedMigrateException
27 from Products.ZenUtils.ZenScriptBase import ZenScriptBase
28 from Products.ZenUtils.Utils import cleanupSkins, zenPath
29 import Products.ZenModel.ZenPackLoader as ZPL
30 from Products.ZenModel.ZenPackLoader import CONFIG_FILE, CONFIG_SECTION_ABOUT
31 import ZenPackCmd as EggPackCmd
32
33 HIGHER_THAN_CRITICAL = 100
34
35 -def RemoveZenPack(dmd, packName, log=None,
36 skipDepsCheck=False, leaveObjects=True,
37 deleteFiles=True):
74
75
77 "Manage ZenPacks"
78
79
81 "Execute the user's request"
82 if self.args:
83 print "Require one of --install, --remove or --list flags."
84 self.parser.print_help()
85 return
86
87 if self.options.installPackName:
88 eggInstall = (self.options.installPackName.lower().endswith('.egg')
89 or os.path.exists(os.path.join(self.options.installPackName,
90 'setup.py')))
91
92
93
94 class ZPProxy:
95 def __init__(self, zpId):
96 self.id = zpId
97 def path(self, *parts):
98 return zenPath('Products', self.id, *parts)
99 if self.options.installPackName and self.options.filesOnly:
100 if eggInstall:
101 return EggPackCmd.InstallZenPack(None,
102 self.options.installPackName,
103 filesOnly=True)
104 packName = self.extract(self.options.installPackName)
105 proxy = ZPProxy(packName)
106 for loader in (ZPL.ZPLDaemons(), ZPL.ZPLBin(), ZPL.ZPLLibExec()):
107 loader.load(proxy, None)
108 return
109 if self.options.removePackName and self.options.filesOnly:
110
111
112 proxy = ZPProxy(self.options.removePackName)
113 for loader in (ZPL.ZPLDaemons(), ZPL.ZPLBin(), ZPL.ZPLLibExec()):
114 loader.unload(proxy, None)
115 os.system('rm -rf %s' % zenPath('Products',
116 self.options.removePackName))
117 return
118
119
120
121 self.connect()
122
123 if not getattr(self.dmd, 'ZenPackManager', None):
124 raise ZenPackNeedMigrateException('Your Zenoss database appears'
125 ' to be out of date. Try running zenmigrate to update.')
126
127 if self.options.installPackName:
128 if eggInstall:
129 return EggPackCmd.InstallEggAndZenPack(
130 self.dmd,
131 self.options.installPackName,
132 link=self.options.link,
133 filesOnly=False,
134 previousVersion= self.options.previousVersion)
135 if not self.preInstallCheck():
136 self.stop('%s not installed' % self.options.installPackName)
137 if os.path.isfile(self.options.installPackName):
138 packName = self.extract(self.options.installPackName)
139 elif os.path.isdir(self.options.installPackName):
140 if self.options.link:
141 packName = self.linkDir(self.options.installPackName)
142 else:
143 packName = self.copyDir(self.options.installPackName)
144 else:
145 self.stop('%s does not appear to be a valid file or directory.'
146 % self.options.installPackName)
147
148
149
150
151
152 skinsSubdir = zenPath('Products', packName, 'skins', packName)
153 if not os.path.exists(skinsSubdir):
154 os.makedirs(skinsSubdir, 0750)
155 self.install(packName)
156
157
158
159
160 elif self.options.removePackName:
161 pack = self.dmd.ZenPackManager.packs._getOb(
162 self.options.removePackName, None)
163 if not pack:
164 raise ZenPackException('ZenPack %s is not installed.' %
165 self.options.removePackName)
166 if pack.isEggPack():
167 return EggPackCmd.RemoveZenPack(self.dmd,
168 self.options.removePackName)
169 RemoveZenPack(self.dmd, self.options.removePackName, self.log)
170
171 elif self.options.list:
172 for zpId in self.dmd.ZenPackManager.packs.objectIds():
173 try:
174 zp = self.dmd.ZenPackManager.packs._getOb(zpId, None)
175 except AttributeError:
176 zp = None
177 if not zp:
178 desc = 'broken'
179 elif zp.isEggPack():
180 desc = zp.eggPath()
181 else:
182 desc = zp.path()
183 print('%s (%s)' % (zpId, desc))
184
185 transaction.commit()
186
187
225
226
228
229 zp = None
230 try:
231
232 log = logging.getLogger('Zope.ZCatalog')
233 oldLevel = log.getEffectiveLevel()
234 log.setLevel(HIGHER_THAN_CRITICAL)
235 zp = self.dmd.ZenPackManager.packs._getOb(packName)
236 self.log.info('Upgrading %s' % packName)
237 zp.upgrade(self.app)
238 except AttributeError:
239 try:
240 module = __import__('Products.' + packName, globals(), {}, [''])
241 zp = module.ZenPack(packName)
242 except (ImportError, AttributeError), ex:
243 self.log.debug("Unable to find custom ZenPack (%s), "
244 "defaulting to generic ZenPack",
245 ex)
246 zp = ZenPack(packName)
247 self.dmd.ZenPackManager.packs._setObject(packName, zp)
248 zp = self.dmd.ZenPackManager.packs._getOb(packName)
249 zp.install(self.app)
250 finally:
251 log.setLevel(oldLevel)
252 if zp:
253 for required in zp.requires:
254 try:
255 self.dmd.ZenPackManager.packs._getOb(required)
256 except:
257 self.log.error("Pack %s requires pack %s: not installing",
258 packName, required)
259 return
260 transaction.commit()
261
263 "Unpack a ZenPack, and return the name"
264 if not os.path.isfile(fname):
265 self.stop('Unable to open file "%s"' % fname)
266 zf = ZipFile(fname)
267 name = zf.namelist()[0]
268 packName = name.split('/')[0]
269 self.log.debug('Extracting ZenPack "%s"' % packName)
270 for name in zf.namelist():
271 fullname = zenPath('Products', name)
272 self.log.debug('Extracting %s' % name)
273 if name.find('/.svn') > -1: continue
274 if name.endswith('~'): continue
275 if name.endswith('/'):
276 if not os.path.exists(fullname):
277 os.makedirs(fullname, 0750)
278 else:
279 base = os.path.dirname(fullname)
280 if not os.path.isdir(base):
281 os.makedirs(base, 0750)
282 file(fullname, 'wb').write(zf.read(name))
283 return packName
284
285
287 '''Copy an unzipped zenpack to the appropriate location.
288 Return the name.
289 '''
290
291 if srcDir.endswith('/'):
292 srcDir = srcDir[:-1]
293
294 if not os.path.isdir(srcDir):
295 self.stop('Specified directory does not appear to exist: %s' %
296 srcDir)
297
298
299 packName = os.path.split(srcDir)[1]
300 root = zenPath('Products', packName)
301
302
303 if os.path.exists(root) and os.path.samefile(root, srcDir):
304 self.log.debug('Directory already in %s, not copying.',
305 zenPath('Products'))
306 return packName
307
308
309 self.log.debug('Copying %s' % packName)
310 result = os.system('cp -r %s %s' % (srcDir, zenPath('Products')))
311 if result == -1:
312 self.stop('Error copying %s to %s' % (srcDir, zenPath('Products')))
313
314 return packName
315
316
318 '''Symlink the srcDir into Products
319 Return the name.
320 '''
321
322 if srcDir.endswith('/'):
323 srcDir = srcDir[:-1]
324
325
326 srcDir = os.path.abspath(srcDir)
327
328 if not os.path.isdir(srcDir):
329 self.stop('Specified directory does not appear to exist: %s' %
330 srcDir)
331
332
333 packName = os.path.split(srcDir)[1]
334 root = zenPath('Products', packName)
335
336
337 if os.path.exists(root) and os.path.samefile(root, srcDir):
338 self.log.debug('Directory already in %s, not copying.',
339 zenPath('Products'))
340 return packName
341
342 targetdir = zenPath("Products", packName)
343 cmd = 'test -d %s && rm -rf %s' % (targetdir, targetdir)
344 os.system(cmd)
345 cmd = 'ln -s %s %s' % (srcDir, zenPath("Products"))
346 os.system(cmd)
347
348 return packName
349
350
351 - def stop(self, why):
352 self.log.error("zenpack stopped: %s", why)
353 sys.exit(1)
354
355
357 self.parser.add_option('--install',
358 dest='installPackName',
359 default=None,
360 help="Path to the ZenPack to install.")
361
362
363
364
365
366
367
368
369
370
371 self.parser.add_option('--remove',
372 dest='removePackName',
373 default=None,
374 help="Name of the ZenPack to remove.")
375 self.parser.add_option('--list',
376 dest='list',
377 action="store_true",
378 default=False,
379 help='List installed ZenPacks')
380 self.parser.add_option('--link',
381 dest='link',
382 action="store_true",
383 default=False,
384 help="Install the ZenPack in place, without "
385 "copying into $ZENHOME/ZenPacks.")
386 self.parser.add_option('--files-only',
387 dest='filesOnly',
388 action="store_true",
389 default=False,
390 help='Install the ZenPack files onto the '
391 'filesystem, but do not install the '
392 'ZenPack into Zenoss.')
393 self.parser.add_option('--previousversion',
394 dest='previousVersion',
395 default=None,
396 help="Previous version of the zenpack;"
397 ' used during upgrades')
398
399 ZenScriptBase.buildOptions(self)
400
401 if __name__ == '__main__':
402 logging.basicConfig()
403 log = logging.getLogger('zen.ZenPackCmd')
404 try:
405 zp = ZenPackCmd()
406 zp.run()
407 except ConflictError:
408 raise
409 except:
410 log.exception('zenpack command failed')
411 sys.exit(-1)
412