1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = "Manage ZenPacks"
15
16 import Globals
17 from ZODB.transact import transact
18 from Products.ZenUtils.ZenScriptBase import ZenScriptBase
19 from Products.ZenUtils.Utils import cleanupSkins, zenPath, binPath, getObjByPath
20
21 from Products.ZenModel.ZenPack import ZenPackException, \
22 ZenPackNotFoundException, \
23 ZenPackNeedMigrateException
24 from Products.ZenModel.ZenPack import ZenPackDependentsException
25 from Products.ZenModel.ZenPack import ZenPack
26 from Products.ZenUtils.PkgResources import pkg_resources
27 from Products.Zuul.utils import CatalogLoggingFilter
28 import Products.ZenModel.ZenPackLoader as ZPL
29 import zenpack as oldzenpack
30 import transaction
31 import os, sys
32 import shutil
33 import string
34 import tempfile
35 import subprocess
36 import socket
37 import logging
38 import zExceptions
39
40
41 log = logging.getLogger('zen.ZenPackCMD')
42
43
44
45 FQDN = socket.getfqdn()
46
47 ZEN_PACK_INDEX_URL = ''
48
49
50 ZENPACK_ENTRY_POINT = 'zenoss.zenpacks'
57 """
58 Create the zenpack in the filesystem.
59 The zenpack is not installed in Zenoss, it is simply created in
60 the $ZENHOME/ZenPacks directory. Usually this should be followed
61 with a "zenpack install" call.
62 zpId should already be valid, scrubbed value.
63 prevZenPackName is written to PREV_ZENPACK_NAME in setup.py.
64 """
65 parts = zpId.split('.')
66
67
68 srcDir = zenPath('Products', 'ZenModel', 'ZenPackTemplate')
69 devDir = zenPath('ZenPacks')
70 if not os.path.exists(devDir):
71 os.mkdir(devDir, 0750)
72 destDir = os.path.join(devDir, zpId)
73 shutil.copytree(srcDir, destDir, symlinks=False)
74 os.system('find %s -name .svn | xargs rm -rf' % destDir)
75
76
77 packages = []
78 for i in range(len(parts)):
79 packages.append('.'.join(parts[:i+1]))
80 mapping = dict(
81 NAME = zpId,
82 VERSION = '1.0.0',
83 AUTHOR = '',
84 LICENSE = '',
85 NAMESPACE_PACKAGES = packages[:-1],
86 PACKAGES = packages,
87 INSTALL_REQUIRES = [],
88 COMPAT_ZENOSS_VERS = '',
89 PREV_ZENPACK_NAME = prevZenPackName,
90 )
91 WriteSetup(os.path.join(destDir, 'setup.py'), mapping)
92
93
94 base = destDir
95 for part in parts[:-1]:
96 base = os.path.join(base, part)
97 os.mkdir(base)
98 f = open(os.path.join(base, '__init__.py'), 'w')
99 f.write("__import__('pkg_resources').declare_namespace(__name__)\n")
100 f.close()
101 base = os.path.join(base, parts[-1])
102 shutil.move(os.path.join(destDir, 'CONTENT'), base)
103
104 return destDir
105
108 """
109 """
110 f = file(setupPath, 'r')
111 lines = f.readlines()
112 f.close()
113
114 newLines = []
115 for i, line in enumerate(lines):
116 if line.startswith('STOP_REPLACEMENTS'):
117 newLines += lines[i:]
118 break
119 key = line.split('=')[0].strip()
120 if key in values:
121 value = values[key]
122 if isinstance(value, basestring):
123 fmt = '%s = "%s"\n'
124 else:
125 fmt = '%s = %s\n'
126 newLines.append(fmt % (key, value))
127 else:
128 newLines.append(line)
129
130 f = file(setupPath, 'w')
131 f.writelines(newLines)
132 f.close()
133
136 """
137 Return tuple (bool, string) where first element is true if a new zenpack
138 can be created with the given info and false if not. If first element
139 is True then the second part of the tuple contains the scrubbed ZenPack id.
140 If the first part is False then the second contains an explanatory
141 message.
142 """
143
144 (allowable, idOrMsg) = ScrubZenPackId(zpId)
145 if allowable:
146 zpId = idOrMsg
147 else:
148 return (False, idOrMsg)
149
150
151 if dmd:
152 if zpId in dmd.ZenPackManager.packs.objectIds():
153 return (False, 'A ZenPack named %s already exists.' % zpId)
154
155
156
157
158
159
160 if os.path.exists(zenPath('ZenPacks', zpId)):
161 return (False, 'A directory named %s already exists' % zpId +
162 ' in $ZENHOME/ZenPacks. Use a different name'
163 ' or remove that directory.')
164
165 return (True, idOrMsg)
166
169 """
170 If the given name conforms to ZenPack naming rules, or can easily be
171 modified to do so, then return (True, scrubbedName) where scrubbedName
172 is either name or a slightly modified name. If the given name does
173 not conform to naming rules and we can't easily modify it to do so
174 then return (False, errorMsg) where errorMsg describes why name
175 is unacceptable.
176 """
177 parts = name.split('.')
178
179
180
181 parts = [p.strip() for p in parts]
182 parts = [p for p in parts if p]
183
184
185 if parts[0] != 'ZenPacks':
186 if parts[0].lower() == 'zenpacks':
187 parts[0] = 'ZenPacks'
188 else:
189 parts.insert(0, 'ZenPacks')
190
191
192 if len(parts) < 3:
193 return (False, 'ZenPack names must contain at least three package '
194 'names separated by periods.')
195
196
197 for p in parts:
198 if p[0] not in string.letters:
199 return (False, 'Each package name must start with a letter.')
200
201
202 allowable = string.letters + string.digits + '_'
203 for p in parts:
204 for c in p:
205 if c not in allowable:
206 return (False, 'Package names may only contain letters, '
207 'numbers and underscores.')
208
209 return (True, '.'.join(parts))
210
220
221 -def InstallEggAndZenPack(dmd, eggPath, link=False,
222 filesOnly=False, sendEvent=True,
223 previousVersion=None, forceRunExternal=False):
224 """
225 Installs the given egg, instantiates the ZenPack, installs in
226 dmd.ZenPackManager.packs, and runs the zenpacks's install method.
227 Returns a list of ZenPacks that were installed.
228 """
229 zenPacks = []
230 nonCriticalErrorEncountered = False
231 try:
232 zpDists = InstallEgg(dmd, eggPath, link=link)
233 for d in zpDists:
234 try:
235 zp = InstallDistAsZenPack(dmd,
236 d,
237 eggPath,
238 link,
239 filesOnly=filesOnly,
240 previousVersion=previousVersion,
241 forceRunExternal=forceRunExternal)
242 zenPacks.append(zp)
243 except NonCriticalInstallError, ex:
244 nonCriticalErrorEncountered = True
245 if sendEvent:
246 ZPEvent(dmd, 3, ex.message)
247 except:
248 if sendEvent:
249 ZPEvent(dmd, 4, 'Error installing ZenPack %s' % eggPath,
250 '%s: %s' % sys.exc_info()[:2])
251 raise
252 if sendEvent:
253 zenPackIds = [zp.id for zp in zenPacks]
254 if zenPackIds:
255 ZPEvent(dmd, 2, 'Installed ZenPacks %s' % ','.join(zenPackIds))
256 elif not nonCriticalErrorEncountered:
257 ZPEvent(dmd, 4, 'Unable to install %s' % eggPath)
258 return zenPacks
259
262 """
263 Install the given egg and add to the current working set.
264 This does not install the egg as a ZenPack.
265 Return a list of distributions that should be installed as ZenPacks.
266 """
267 eggPath = os.path.abspath(eggPath)
268 zenPackDir = zenPath('ZenPacks')
269 eggInZenPacksDir = eggPath.startswith(zenPackDir + '/')
270
271
272 CreateZenPacksDir()
273
274
275 if link:
276 cmd = ('%s setup.py develop ' % binPath('python') +
277 '--site-dirs=%s ' % zenPackDir +
278 '-d %s' % zenPackDir)
279 p = subprocess.Popen(cmd,
280 stdout=subprocess.PIPE,
281 stderr=subprocess.PIPE,
282 shell=True,
283 cwd=eggPath)
284 out, err = p.communicate()
285 p.wait()
286 if p.returncode:
287 DoEasyUninstall(eggPath)
288 raise ZenPackException('Error installing the egg (%s): %s' %
289 (p.returncode, err))
290 zpDists = AddDistToWorkingSet(eggPath)
291 else:
292 try:
293 zpDists = DoEasyInstall(eggPath)
294 except:
295 DoEasyUninstall(eggPath)
296 raise
297
298
299
300
301
302
303
304
305
306
307
308 return zpDists
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 -def InstallDistAsZenPack(dmd, dist, eggPath, link=False, filesOnly=False,
324 previousVersion=None, forceRunExternal=False):
325 """
326 Given an installed dist, install it into Zenoss as a ZenPack.
327 Return the ZenPack instance.
328 """
329 @transact
330 def transactional_actions():
331
332 entryMap = pkg_resources.get_entry_map(dist, ZENPACK_ENTRY_POINT)
333 if not entryMap or len(entryMap) > 1:
334 raise ZenPackException('A ZenPack egg must contain exactly one'
335 ' zenoss.zenpacks entry point. This egg appears to contain'
336 ' %s such entry points.' % len(entryMap))
337 packName, packEntry = entryMap.items()[0]
338 runExternalZenpack = True
339
340
341 existing = dmd.ZenPackManager.packs._getOb(packName, None)
342 if existing:
343 log.info("Previous ZenPack exists with same name %s" % packName)
344 if filesOnly or not existing:
345
346
347 runExternalZenpack = False
348 module = packEntry.load()
349 if hasattr(module, 'ZenPack'):
350 zenPack = module.ZenPack(packName)
351 else:
352 zenPack = ZenPack(packName)
353 zenPack.eggPack = True
354 CopyMetaDataToZenPackObject(dist, zenPack)
355 if filesOnly:
356 for loader in (ZPL.ZPLDaemons(), ZPL.ZPLBin(), ZPL.ZPLLibExec()):
357 loader.load(zenPack, None)
358
359
360 if not filesOnly:
361
362
363
364
365 existing = dmd.ZenPackManager.packs._getOb(packName, None)
366 if not existing and zenPack.prevZenPackName:
367 existing = dmd.ZenPackManager.packs._getOb(
368 zenPack.prevZenPackName, None)
369
370 deferFileDeletion = False
371 packables = []
372 upgradingFrom = None
373 if existing:
374 upgradingFrom = existing.version
375 for p in existing.packables():
376 packables.append(p)
377 existing.packables.removeRelation(p)
378 if existing.isEggPack():
379 forceNoFileDeletion = existing.eggPath() == dist.location
380 RemoveZenPack(dmd, existing.id,
381 skipDepsCheck=True, leaveObjects=True,
382 forceNoFileDeletion=forceNoFileDeletion,
383 uninstallEgg=False)
384 else:
385
386
387 deferFileDeletion = True
388 oldzenpack.RemoveZenPack(dmd, existing.id,
389 skipDepsCheck=True, leaveObjects=True,
390 deleteFiles=False)
391 if runExternalZenpack or forceRunExternal:
392 log.info("installing zenpack %s; launching process" % packName)
393 cmd = [binPath('zenpack')]
394 if link:
395 cmd += ["--link"]
396 cmd += ["--install", eggPath]
397 if upgradingFrom:
398 cmd += ['--previousversion', upgradingFrom]
399
400 cmdStr = " ".join(cmd)
401 log.debug("launching sub process command: %s" % cmdStr)
402 p = subprocess.Popen(cmdStr,
403 shell=True)
404 out, err = p.communicate()
405 p.wait()
406 if p.returncode:
407 raise ZenPackException('Error installing the egg (%s): %s' %
408 (p.returncode, err))
409 dmd._p_jar.sync()
410 else:
411 dmd.ZenPackManager.packs._setObject(packName, zenPack)
412 zenPack = dmd.ZenPackManager.packs._getOb(packName)
413
414
415
416 zenPack.prevZenPackVersion = previousVersion
417 zenPack.install(dmd)
418 zenPack.prevZenPackVersion = None
419
420 try:
421 zenPack = dmd.ZenPackManager.packs._getOb(packName)
422 for p in packables:
423 pId = p.getPrimaryId()
424 try:
425
426
427 getObjByPath(dmd, pId)
428 log.debug("adding packable relation for id %s", pId)
429 zenPack.packables.addRelation(p)
430 except (KeyError, zExceptions.NotFound):
431 log.debug('did not find packable %s',pId)
432 except AttributeError, e:
433
434
435 if not runExternalZenpack:
436 raise
437
438
439
440
441 if str(e) == "'ZenPack' object has no attribute '__of__'":
442 zenPack = ZenPack(packName)
443 else:
444
445
446
447 message = "There has been an error during the post-" + \
448 "installation steps for the zenpack %s. In " + \
449 "most cases, no further action is required. If " + \
450 "issues persist, please reinstall this zenpack."
451 message = message % packName
452 log.warning( message )
453 raise NonCriticalInstallError( message )
454
455 cleanupSkins(dmd)
456 return zenPack, deferFileDeletion, existing
457
458 zenPack, deferFileDeletion, existing = transactional_actions()
459
460 if not filesOnly and deferFileDeletion:
461
462
463
464 oldZpDir = zenPath('Products', existing.id)
465 if os.path.islink(oldZpDir):
466 os.remove(oldZpDir)
467 else:
468 shutil.rmtree(oldZpDir)
469
470 return zenPack
471
474 """
475 Find installed eggs that provide a zenoss.zenpacks entry point.
476 Return a list of distributions whose ZenPacks need to be installed
477 or upgraded. The list is sorted into the order in which this needs to
478 happen.
479 """
480
481
482 entries = set()
483 parse_version = pkg_resources.parse_version
484 for entry in pkg_resources.iter_entry_points(ZENPACK_ENTRY_POINT):
485 packName = entry.name
486 packVers = entry.dist.version
487 existing = dmd.ZenPackManager.packs._getOb(packName, None)
488 if existing and existing.isEggPack():
489
490
491
492 if parse_version(packVers) >= parse_version(existing.version):
493 entries.add(entry)
494 else:
495 entries.add(entry)
496
497
498
499
500
501
502
503 orderedEntries = []
504 entriesByName = dict((e.name, e) for e in entries)
505
506 def AddEntryAndProcessDeps(e):
507 orderedEntries.append(e)
508 for name in [r.project_name for r in e.dist.requires()]:
509 if name in [e.name for e in orderedEntries]:
510
511
512
513
514
515 raise ZenPackException('Unable to resolve ZenPack dependencies.'
516 ' Try installing dependencies first.')
517 if name in entriesByName:
518
519
520 AddEntryAndProcessDeps(entriesByName[name])
521 else:
522
523
524
525
526 pass
527
528 if zenPackId not in entriesByName:
529 if zenPackId in dmd.ZenPackManager.packs.objectIds():
530 return []
531 else:
532 raise ZenPackException('Unable to discover ZenPack named %s' %
533 zenPackId)
534 AddEntryAndProcessDeps(entriesByName[zenPackId])
535 orderedEntries.reverse()
536 return [e.dist for e in orderedEntries]
537
540 """
541 Given the path to a dist (an egg) add it to the current working set.
542 This is basically a pkg_resources-friendly way of adding it to
543 sys.path.
544 Return a list of all distributions on distPath that appear to
545 be ZenPacks.
546 """
547 zpDists = []
548 for d in pkg_resources.find_distributions(distPath):
549 pkg_resources.working_set.add(d)
550 pkg_resources.require(d.project_name)
551 if d.project_name.startswith('ZenPacks.'):
552 zpDists.append(d)
553 return zpDists
554
557 """
558 Return a dictionary containing the egg metadata
559 """
560 info = {}
561 if dist.has_metadata('PKG-INFO'):
562 lines = dist.get_metadata('PKG-INFO')
563 for line in pkg_resources.yield_lines(lines):
564 key, value = line.split(':', 1)
565 info[key.strip()] = value.strip()
566 if dist.has_metadata('zenpack_info'):
567 lines = dist.get_metadata('zenpack_info')
568 for line in pkg_resources.yield_lines(lines):
569 key, value = line.split(':', 1)
570 info[key.strip()] = value.strip()
571 return info
572
595
598 """
599 Make sure $ZENHOME/ZenPacks exists
600 """
601 zpDir = zenPath('ZenPacks')
602 if not os.path.isdir(zpDir):
603 os.mkdir(zpDir, 0750)
604
607 """
608 Use easy_install to install an egg from the filesystem.
609 easy_install will install the egg, but does not install it into
610 Zenoss as ZenPacks.
611 Returns a list of distributions that were installed that appear
612 to be ZenPacks.
613 """
614 from setuptools.command import easy_install
615
616
617 CreateZenPacksDir()
618
619
620 _, tempPath = tempfile.mkstemp(prefix='zenpackcmd-easyinstall')
621
622
623
624 eggPaths = set()
625 try:
626
627 args = ['--site-dirs', zenPath('ZenPacks'),
628 '-d', zenPath('ZenPacks'),
629
630 '--allow-hosts', 'None',
631 '--record', tempPath,
632 '--quiet',
633 eggPath]
634 easy_install.main(args)
635
636 f = open(tempPath, 'r')
637 marker = '.egg/'
638 markerOffset = len(marker)-1
639 for l in f.readlines():
640 i = l.find(marker)
641 if i > 0:
642 eggPaths.add(l[:i+markerOffset])
643 finally:
644 os.remove(tempPath)
645
646 zpDists = []
647 for path in eggPaths:
648 zpDists += AddDistToWorkingSet(path)
649 return zpDists
650
658 """
659 Fetch the named zenpack and all its dependencies and install them.
660 Return a list of the ZenPacks that were installed.
661 """
662 zenPacks = []
663 try:
664 zpDists = FetchZenPack(zenPackName, zenPackVersion)
665 for d in zpDists:
666 zenPacks.append(InstallDistAsZenPack(dmd, d))
667 except:
668 if sendEvent:
669 ZPEvent(dmd, 4, 'Failed to install ZenPack %s' % zenPackName,
670 '%s: %s' % sys.exc_info()[:2])
671 raise
672 if sendEvent:
673 zenPackIds = [z.id for z in zenPacks]
674 if zenPackIds:
675 ZPEvent(dmd, 2, 'Installed ZenPacks: %s' % ', '.join(zenPackIds))
676 if zenPackName not in zenPackIds:
677 ZPEvent(dmd, 4, 'Unable to install ZenPack %s' % zenPackName)
678 return zenPacks
679
682 """
683 Use easy_install to retrieve the given zenpack and any dependencies.
684 easy_install will install the eggs, but does not install them into
685 Zenoss as ZenPacks.
686 Return a list of distributions just installed that appear to be
687 ZenPacks.
688
689 NB: This should be refactored. It shares most of its code with
690 DoEasyInstall()
691 """
692 from setuptools.command import easy_install
693
694
695 CreateZenPacksDir()
696
697
698 _, tempPath = tempfile.mkstemp(prefix='zenpackcmd-easyinstall')
699
700
701
702 eggPaths = set()
703 try:
704
705 args = ['--site-dirs', zenPath('ZenPacks'),
706 '-d', zenPath('ZenPacks'),
707 '-i', ZEN_PACK_INDEX_URL,
708 '--allow-hosts', 'None',
709 '--record', tempPath,
710 '--quiet',
711 zenPackName]
712 easy_install.main(args)
713
714 f = open(tempPath, 'r')
715 marker = '.egg/'
716 markerOffset = len(marker)-1
717 for l in f.readlines():
718 i = l.find(marker)
719 if i > 0:
720 eggPaths.add(l[:i+markerOffset])
721 finally:
722 os.remove(tempPath)
723
724 zpDists = []
725 for path in eggPaths:
726 zpDists += AddDistToWorkingSet(path)
727 return zpDists
728
729
730 -def UploadZenPack(dmd, packName, project, description, znetUser, znetPass):
766
767
768
769
770
771
772
773 -def RemoveZenPack(dmd, packName, filesOnly=False, skipDepsCheck=False,
774 leaveObjects=False, sendEvent=True,
775 forceNoFileDeletion=False, uninstallEgg=True):
776 """
777 Remove the given ZenPack from Zenoss.
778 Whether the ZenPack will be removed from the filesystem or not
779 depends on the result of the ZenPack's shouldDeleteFilesOnRemoval method.
780 """
781 try:
782 if filesOnly:
783 skipDepsCheck = True
784
785
786 if not skipDepsCheck:
787 deps = GetDependents(dmd, packName)
788 if deps:
789 raise ZenPackDependentsException('%s cannot be removed ' % packName +
790 'because it is required by %s' % ', '.join(deps))
791
792 if not filesOnly:
793
794 zp = None
795 try:
796 zp = dmd.ZenPackManager.packs._getOb(packName)
797 except AttributeError, ex:
798 raise ZenPackNotFoundException('No ZenPack named %s is installed' %
799 packName)
800
801
802 logFilter = None
803 if not getattr(dmd.zport, '_zencatalog_completed', False):
804 logFilter = CatalogLoggingFilter()
805 logging.getLogger('Zope.ZCatalog').addFilter(logFilter)
806 try:
807 zp.remove(dmd, leaveObjects)
808 dmd.ZenPackManager.packs._delObject(packName)
809 transaction.commit()
810 finally:
811
812 if logFilter is not None:
813 logging.getLogger('Zope.ZCatalog').removeFilter(logFilter)
814
815
816
817
818
819 try:
820 dist = zp.getDistribution()
821 except pkg_resources.DistributionNotFound:
822 dist = None
823 if dist:
824
825
826 deleteFiles = zp.shouldDeleteFilesOnRemoval()
827 if uninstallEgg:
828 if zp.isDevelopment():
829 zenPackDir = zenPath('ZenPacks')
830 cmd = ('%s setup.py develop -u '
831 % binPath('python') +
832 '--site-dirs=%s ' % zenPackDir +
833 '-d %s' % zenPackDir)
834 p = subprocess.Popen(cmd,
835 stdout=subprocess.PIPE,
836 stderr=subprocess.PIPE,
837 shell=True,
838 cwd=zp.eggPath())
839 out, err = p.communicate()
840 code = p.wait()
841 if code:
842 raise ZenPackException(err)
843 else:
844 DoEasyUninstall(packName)
845
846
847
848
849
850
851
852
853
854 if deleteFiles and not forceNoFileDeletion:
855 eggDir = zp.eggPath()
856 if os.path.islink(eggDir):
857 os.remove(eggDir)
858 else:
859 shutil.rmtree(eggDir)
860 cleanupSkins(dmd)
861 transaction.commit()
862 except:
863 if sendEvent:
864 ZPEvent(dmd, 4, 'Error removing ZenPack %s' % packName,
865 '%s: %s' % sys.exc_info()[:2])
866 raise
867 if sendEvent:
868 ZPEvent(dmd, 2, 'Removed ZenPack %s' % packName)
869
872 """
873 Execute the easy_install command to unlink the given egg.
874 What this is really doing is switching the egg to be in
875 multiple-version mode, however this is the first step in deleting
876 an egg as described here:
877 http://peak.telecommunity.com/DevCenter/EasyInstall#uninstalling-packages
878 """
879 from setuptools.command import easy_install
880 args = ['--site-dirs', zenPath('ZenPacks'),
881 '-d', zenPath('ZenPacks'),
882
883 '--quiet',
884 '-m',
885 name]
886 easy_install.main(args)
887
890 """
891 Returns a tuple of (canRemove, otherDependents)
892 canRemove is True if the listed zenPacks have no dependents not also
893 listed in packNames, False otherwise.
894 otherDependents is a list of zenpack names not in packNames that
895 depend on one or more of the packs in packNames.
896 """
897 unhappy = set()
898 for name in packNames:
899 deps = GetDependents(dmd, name)
900 unhappy.update(set(dep for dep in deps if dep not in packNames))
901 return (not unhappy, list(unhappy))
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930 -def GetDependents(dmd, packName):
931 """
932 Return a list of installed ZenPack ids that list packName as a dependency
933 """
934 return [zp.id for zp in dmd.ZenPackManager.packs()
935 if zp.id != packName and packName in zp.dependencies]
936
937
938
939
940
941
942
943 -def ZPEvent(dmd, severity, summary, message=None):
953
956 """
957 Utilities for creating, installing, removing ZenPacks.
958
959 NOTE: Users will probably invoke zenpack from the command line, which
960 runs zenpack.py rather than this file. zenpack.py calls functions
961 in this module when it detects that new-style (egg) ZenPacks are involved.
962 The plan is that once support for old-style (non-egg) ZenPacks is dropped
963 zenpack.py can go away and this will take its place. Until then this
964 script can be invoked directly via the zenpackcmd script if desired.
965 Invoking this script directly has the benefit of slightly better
966 progress/status output to stdout.
967 """
968
970 """
971 Execute the user's request.
972 """
973
974 self.connect()
975 def PrintInstalled(installed, eggOnly=False):
976 if installed:
977 if eggOnly:
978 names = [i['id'] for i in installed]
979 what = 'ZenPack egg'
980 else:
981 names = [i.id for i in installed]
982 what = 'ZenPack'
983 print('Installed %s%s: %s' % (
984 what,
985 len(names) != 1 and 's' or '',
986 ', '.join(names)))
987 else:
988 print('No ZenPacks installed.')
989
990 if not getattr(self.dmd, 'ZenPackManager', None):
991 raise ZenPackNeedMigrateException('Your Zenoss database appears'
992 ' to be out of date. Try running zenmigrate to update.')
993 if self.options.eggOnly and self.options.eggPath:
994 zpDists = InstallEgg(self.dmd, self.options.eggPath,
995 link=self.options.link)
996 PrintInstalled([{'id':d.project_name} for d in zpDists],
997 eggOnly=True)
998 if self.options.eggPath:
999 installed = InstallEggAndZenPack(
1000 self.dmd, self.options.eggPath,
1001 link=self.options.link,
1002 filesOnly=self.options.filesOnly,
1003 previousVersion= self.options.previousVersion)
1004 PrintInstalled(installed)
1005 elif self.options.fetch:
1006 installed = FetchAndInstallZenPack(self.dmd, self.options.fetch)
1007 PrintInstalled(installed)
1008 elif self.options.upload:
1009 return UploadZenPack(self.dmd, self.options.upload,
1010 self.options.znetProject,
1011 self.options.uploadDesc,
1012 self.options.znetUser,
1013 self.options.znetPass)
1014 elif self.options.removePackName:
1015 try:
1016 RemoveZenPack(self.dmd, self.options.removePackName)
1017 print('Removed ZenPack: %s' % self.options.removePackName)
1018 except ZenPackNotFoundException, e:
1019 sys.stderr.write(str(e) + '\n')
1020 elif self.options.list:
1021 self.list()
1022 else:
1023 self.parser.print_help()
1024
1025
1027 self.parser.add_option('--install',
1028 dest='eggPath',
1029 default=None,
1030 help="name of the pack to install")
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 self.parser.add_option('--link',
1068 dest='link',
1069 action='store_true',
1070 default=False,
1071 help='Install the ZenPack in its current '
1072 'location, do not copy to $ZENHOME/ZenPacks. '
1073 'Also mark ZenPack as editable. '
1074 'This only works with source directories '
1075 'containing setup.py files, not '
1076 'egg files.')
1077 self.parser.add_option('--remove',
1078 dest='removePackName',
1079 default=None,
1080 help="name of the pack to remove")
1081 self.parser.add_option('--leave-objects',
1082 dest='leaveObjects',
1083 default=False,
1084 action='store_true',
1085 help="When specified with --remove then objects"
1086 ' provided by the ZenPack and those'
1087 ' depending on the ZenPack are not deleted.'
1088 ' This may result in broken objects in your'
1089 ' database unless the ZenPack is'
1090 ' reinstalled.')
1091 self.parser.add_option('--files-only',
1092 dest='filesOnly',
1093 action="store_true",
1094 default=False,
1095 help='install onto filesystem but not into '
1096 'zenoss')
1097 self.parser.add_option('--previousversion',
1098 dest='previousVersion',
1099 default=None,
1100 help="Previous version of the zenpack;"
1101 ' used during upgrades')
1102 self.parser.prog = "zenpack"
1103 ZenScriptBase.buildOptions(self)
1104
1105
1106 if __name__ == '__main__':
1107 try:
1108 zp = ZenPackCmd()
1109 zp.run()
1110 except ZenPackException, e:
1111 sys.stderr.write('%s\n' % str(e))
1112 sys.exit(-1)
1113