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