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
430 getObjByPath(dmd, pId)
431 log.debug("adding packable relation for id %s", pId)
432 zenPack.packables.addRelation(p)
433 except (KeyError, zExceptions.NotFound):
434 log.debug('did not find packable %s',pId)
435 except AttributeError, e:
436
437
438 if not runExternalZenpack:
439 raise
440
441
442
443
444 if str(e) == "'ZenPack' object has no attribute '__of__'":
445 zenPack = ZenPack(packName)
446 else:
447
448
449
450 message = "There has been an error during the post-" + \
451 "installation steps for the zenpack %s. In " + \
452 "most cases, no further action is required. If " + \
453 "issues persist, please reinstall this zenpack."
454 message = message % packName
455 log.warning( message )
456 raise NonCriticalInstallError( message )
457
458 if deferFileDeletion:
459
460
461
462 oldZpDir = zenPath('Products', existing.id)
463 if os.path.islink(oldZpDir):
464 os.remove(oldZpDir)
465 else:
466 shutil.rmtree(oldZpDir)
467
468 cleanupSkins(dmd)
469 transaction.commit()
470 return zenPack
471
472
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
538
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
555
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
573
595
596
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
605
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
651
652
653
654
655
656
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
680
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 zp.remove(dmd, leaveObjects)
801 dmd.ZenPackManager.packs._delObject(packName)
802 transaction.commit()
803
804
805
806
807
808 try:
809 dist = zp.getDistribution()
810 except pkg_resources.DistributionNotFound:
811 dist = None
812 if dist:
813
814
815 deleteFiles = zp.shouldDeleteFilesOnRemoval()
816 if uninstallEgg:
817 if zp.isDevelopment():
818 zenPackDir = zenPath('ZenPacks')
819 cmd = ('%s setup.py develop -u '
820 % binPath('python') +
821 '--site-dirs=%s ' % zenPackDir +
822 '-d %s' % zenPackDir)
823 p = subprocess.Popen(cmd,
824 stdout=subprocess.PIPE,
825 stderr=subprocess.PIPE,
826 shell=True,
827 cwd=zp.eggPath())
828 out, err = p.communicate()
829 code = p.wait()
830 if code:
831 raise ZenPackException(err)
832 else:
833 DoEasyUninstall(packName)
834
835
836
837
838
839
840
841
842
843 if deleteFiles and not forceNoFileDeletion:
844 eggDir = zp.eggPath()
845 if os.path.islink(eggDir):
846 os.remove(eggDir)
847 else:
848 shutil.rmtree(eggDir)
849 cleanupSkins(dmd)
850 transaction.commit()
851 except:
852 if sendEvent:
853 ZPEvent(dmd, 4, 'Error removing ZenPack %s' % packName,
854 '%s: %s' % sys.exc_info()[:2])
855 raise
856 if sendEvent:
857 ZPEvent(dmd, 2, 'Removed ZenPack %s' % packName)
858
859
861 """
862 Execute the easy_install command to unlink the given egg.
863 What this is really doing is switching the egg to be in
864 multiple-version mode, however this is the first step in deleting
865 an egg as described here:
866 http://peak.telecommunity.com/DevCenter/EasyInstall#uninstalling-packages
867 """
868 from setuptools.command import easy_install
869 args = ['--site-dirs', zenPath('ZenPacks'),
870 '-d', zenPath('ZenPacks'),
871
872 '--quiet',
873 '-m',
874 name]
875 easy_install.main(args)
876
877
879 """
880 Returns a tuple of (canRemove, otherDependents)
881 canRemove is True if the listed zenPacks have no dependents not also
882 listed in packNames, False otherwise.
883 otherDependents is a list of zenpack names not in packNames that
884 depend on one or more of the packs in packNames.
885 """
886 unhappy = set()
887 for name in packNames:
888 deps = GetDependents(dmd, name)
889 unhappy.update(set([dep for dep in deps if dep not in packNames]))
890 return (not unhappy and True or False, list(unhappy))
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
920 """
921 Return a list of installed ZenPack ids that list packName as a dependency
922 """
923 return [zp.id for zp in dmd.ZenPackManager.packs()
924 if zp.id != packName and zp.dependencies.has_key(packName)]
925
926
927
928
929
930
931
932 -def ZPEvent(dmd, severity, summary, message=None):
942
943
945 """
946 Utilities for creating, installing, removing ZenPacks.
947
948 NOTE: Users will probably invoke zenpack from the command line, which
949 runs zenpack.py rather than this file. zenpack.py calls functions
950 in this module when it detects that new-style (egg) ZenPacks are involved.
951 The plan is that once support for old-style (non-egg) ZenPacks is dropped
952 zenpack.py can go away and this will take its place. Until then this
953 script can be invoked directly via the zenpackcmd script if desired.
954 Invoking this script directly has the benefit of slightly better
955 progress/status output to stdout.
956 """
957
959 """
960 Execute the user's request.
961 """
962
963 self.connect()
964 def PrintInstalled(installed, eggOnly=False):
965 if installed:
966 if eggOnly:
967 names = [i['id'] for i in installed]
968 what = 'ZenPack egg'
969 else:
970 names = [i.id for i in installed]
971 what = 'ZenPack'
972 print('Installed %s%s: %s' % (
973 what,
974 len(names) > 1 and 's' or '',
975 ', '.join(names)))
976 else:
977 print('No ZenPacks installed.')
978
979 if not getattr(self.dmd, 'ZenPackManager', None):
980 raise ZenPackNeedMigrateException('Your Zenoss database appears'
981 ' to be out of date. Try running zenmigrate to update.')
982 if self.options.eggOnly and self.options.eggPath:
983 zpDists = InstallEgg(self.dmd, self.options.eggPath,
984 link=self.options.link)
985 PrintInstalled([{'id':d.project_name} for d in zpDists],
986 eggOnly=True)
987 if self.options.eggPath:
988 installed = InstallEggAndZenPack(
989 self.dmd, self.options.eggPath,
990 link=self.options.link,
991 filesOnly=self.options.filesOnly,
992 previousVersion= self.options.previousVersion)
993 PrintInstalled(installed)
994 elif self.options.fetch:
995 installed = FetchAndInstallZenPack(self.dmd, self.options.fetch)
996 PrintInstalled(installed)
997 elif self.options.upload:
998 return UploadZenPack(self.dmd, self.options.upload,
999 self.options.znetProject,
1000 self.options.uploadDesc,
1001 self.options.znetUser,
1002 self.options.znetPass)
1003 elif self.options.removePackName:
1004 try:
1005 RemoveZenPack(self.dmd, self.options.removePackName)
1006 print('Removed ZenPack: %s' % self.options.removePackName)
1007 except ZenPackNotFoundException, e:
1008 sys.stderr.write(str(e) + '\n')
1009 elif self.options.list:
1010 self.list()
1011 else:
1012 self.parser.print_help()
1013
1014
1016 self.parser.add_option('--install',
1017 dest='eggPath',
1018 default=None,
1019 help="name of the pack to install")
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
1048
1049
1050
1051
1052
1053
1054
1055
1056 self.parser.add_option('--link',
1057 dest='link',
1058 action='store_true',
1059 default=False,
1060 help='Install the ZenPack in its current '
1061 'location, do not copy to $ZENHOME/ZenPacks. '
1062 'Also mark ZenPack as editable. '
1063 'This only works with source directories '
1064 'containing setup.py files, not '
1065 'egg files.')
1066 self.parser.add_option('--remove',
1067 dest='removePackName',
1068 default=None,
1069 help="name of the pack to remove")
1070 self.parser.add_option('--leave-objects',
1071 dest='leaveObjects',
1072 default=False,
1073 action='store_true',
1074 help="When specified with --remove then objects"
1075 ' provided by the ZenPack and those'
1076 ' depending on the ZenPack are not deleted.'
1077 ' This may result in broken objects in your'
1078 ' database unless the ZenPack is'
1079 ' reinstalled.')
1080 self.parser.add_option('--files-only',
1081 dest='filesOnly',
1082 action="store_true",
1083 default=False,
1084 help='install onto filesystem but not into '
1085 'zenoss')
1086 self.parser.add_option('--previousversion',
1087 dest='previousVersion',
1088 default=None,
1089 help="Previous version of the zenpack;"
1090 ' used during upgrades')
1091 ZenScriptBase.buildOptions(self)
1092
1093
1094 if __name__ == '__main__':
1095 try:
1096 zp = ZenPackCmd()
1097 zp.run()
1098 except ZenPackException, e:
1099 sys.stderr.write('%s\n' % str(e))
1100 sys.exit(-1)
1101