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