1
2
3
4
5
6
7
8
9
10
11 __doc__ = """ZenPack
12 ZenPacks base definitions
13 """
14
15 import datetime
16 import string
17 import subprocess
18 import os
19 import sys
20 import shutil
21
22 from Globals import InitializeClass
23 from Products.ZenModel.ZenModelRM import ZenModelRM
24 from Products.ZenRelations.RelSchema import *
25 from Products.ZenUtils.Utils import importClass, zenPath
26 from Products.ZenUtils.Version import getVersionTupleFromString
27 from Products.ZenUtils.Version import Version as VersionBase
28 from Products.ZenUtils.PkgResources import pkg_resources
29 from Products.ZenModel import ExampleLicenses
30 from Products.ZenModel.ZenPackLoader import *
31 from Products.ZenWidgets import messaging
32 from AccessControl import ClassSecurityInfo
33 from ZenossSecurity import ZEN_MANAGE_DMD
34 from Acquisition import aq_parent
35 from Products.ZenModel.ZVersion import VERSION as ZENOSS_VERSION
36 from Products.ZenMessaging.audit import audit
37
38
41
44
47
50
53
56
59 VersionBase.__init__(self, 'Zenoss', *args, **kw)
60
61
63 """
64 Given a list of objects, return the sorted list of unique objects
65 where uniqueness is based on the getPrimaryPath() results.
66
67 @param objs: list of objects
68 @type objs: list of objects
69 @return: sorted list of objects
70 @rtype: list of objects
71 """
72
73 objs.sort(key = lambda x: x.getPrimaryPath())
74 result = []
75 for obj in objs:
76 for alreadyInList in result:
77 path = alreadyInList.getPrimaryPath()
78 if obj.getPrimaryPath()[:len(path)] == path:
79 break
80 else:
81 result.append(obj)
82 return result
83
84
86 """
87 Base class for defining migration methods
88 """
89 version = Version(0, 0, 0)
90
92 """
93 ZenPack-specific migrate() method to be overridden
94
95 @param pack: ZenPack object
96 @type pack: ZenPack object
97 """
98 pass
99
101 """
102 ZenPack-specific recover() method to be overridden
103
104 @param pack: ZenPack object
105 @type pack: ZenPack object
106 """
107 pass
108
109
110
111
113 """
114 Base class for ZenPack migrate steps that need to switch classes of
115 datasources and reindex them. This is frequently done in migrate
116 scripts for 2.2 when ZenPacks are migrated to python eggs.
117 """
118
119 dsClass = None
120
121
122
123 oldDsModuleName = ''
124 oldDsClassName = ''
125
126 reIndex = False
127
152
153
155 """
156 The root of all ZenPacks: has no implementation,
157 but sits here to be the target of the Relation
158 """
159
160 objectPaths = None
161
162
163 version = '0.1'
164 author = ''
165 organization = ''
166 url = ''
167 license = ''
168 compatZenossVers = ''
169 prevZenPackName = ''
170 prevZenPackVersion = None
171
172
173
174 eggPack = False
175
176 installableFromUI = True
177
178 requires = ()
179
180 loaders = (ZPLObject(), ZPLReport(), ZPLDaemons(), ZPLBin(), ZPLLibExec(),
181 ZPLSkins(), ZPLDataSources(), ZPLLibraries(), ZPLAbout(),
182 ZPTriggerAction(), ZPZep())
183
184 _properties = ZenModelRM._properties + (
185 {'id':'objectPaths','type':'lines','mode':'w'},
186 {'id':'version', 'type':'string', 'mode':'w', 'description':'ZenPack version'},
187 {'id':'author', 'type':'string', 'mode':'w', 'description':'ZenPack author'},
188 {'id':'organization', 'type':'string', 'mode':'w',
189 'description':'Sponsoring organization for the ZenPack'},
190 {'id':'url', 'type':'string', 'mode':'w', 'description':'Homepage for the ZenPack'},
191 {'id':'license', 'type':'string', 'mode':'w',
192 'description':'Name of the license under which this ZenPack is available'},
193 {'id':'compatZenossVers', 'type':'string', 'mode':'w',
194 'description':'Which Zenoss versions can load this ZenPack'},
195 )
196
197 _relations = (
198
199
200 ('root', ToOne(ToManyCont, 'Products.ZenModel.DataRoot', 'packs')),
201 ('manager',
202 ToOne(ToManyCont, 'Products.ZenModel.ZenPackManager', 'packs')),
203 ("packables", ToMany(ToOne, "Products.ZenModel.ZenPackable", "pack")),
204 )
205
206 factory_type_information = (
207 { 'immediate_view' : 'viewPackDetail',
208 'factory' : 'manage_addZenPack',
209 'actions' :
210 (
211 { 'id' : 'viewPackDetail'
212 , 'name' : 'Detail'
213 , 'action' : 'viewPackDetail'
214 , 'permissions' : ( "Manage DMD", )
215 },
216 )
217 },
218 )
219
220 packZProperties = [
221 ]
222
223 security = ClassSecurityInfo()
224
225
226 - def __init__(self, id, title=None, buildRelations=True):
230
231
246
247
249 """
250 This is essentially an install() call except that a different method
251 is called on the loaders.
252 NB: Newer ZenPacks (egg style) do not use this upgrade method. Instead
253 the proper method is to remove(leaveObjects=True) and install again.
254 See ZenPackCmd.InstallDistAsZenPack().
255
256 @param app: ZenPack
257 @type app: ZenPack object
258 """
259 self.stopDaemons()
260 for loader in self.loaders:
261 loader.upgrade(self, app)
262 self.createZProperties(app)
263 self.migrate()
264 self.startDaemons()
265
266
267 - def remove(self, app, leaveObjects=False):
268 """
269 This prepares the ZenPack for removal but does not actually remove
270 the instance from ZenPackManager.packs This is sometimes called during
271 the course of an upgrade where the loaders' unload methods need to
272 be run.
273
274 @param app: ZenPack
275 @type app: ZenPack object
276 @param leaveObjects: remove zProperties and things?
277 @type leaveObjects: boolean
278 """
279 self.stopDaemons()
280 for loader in self.loaders:
281 loader.unload(self, app, leaveObjects)
282 if not leaveObjects:
283 self.removeZProperties(app)
284 self.removeCatalogedObjects(app)
285
286 - def backup(self, backupDir, logger):
287 """
288 Method called when zenbackup is run. Override in ZenPack to add any
289 ZenPack-specific backup operations.
290
291 @param backupDir: Temporary directory that gets zipped to form backup
292 @type backupDir: string
293 @param logger: Backup log handler
294 @type logger: Log object
295 """
296 pass
297
298 - def restore(self, backupDir, logger):
299 """
300 Method called when zenrestore is run. Override in ZenPack to add any
301 ZenPack-specific restore operations.
302
303 @param backupDir: Temporary directory that contains the unzipped backup
304 @type backupDir: string
305 @param logger: Restore log handler
306 @type logger: Log object
307 """
308 pass
309
310
311 - def migrate(self, previousVersion=None):
354
355
356 - def list(self, app):
357 """
358 Show the list of loaders
359
360 @param app: ZenPack
361 @type app: ZenPack object
362 @return: list of loaders
363 @rtype: list of objects
364 """
365 result = []
366 for loader in self.loaders:
367 result.append((loader.name,
368 [item for item in loader.list(self, app)]))
369 return result
370
372 """
373 Registers ExtJS portlets from a ZenPack. Override in ZenPack. ID and
374 title are required, height and permissions are optional. See
375 ZenWidgets.PortletManager.register_extjsPortlet.
376
377 @return: List of dictionary objects describing a portlet
378 @rtype: List of dicts
379 """
380 return []
381
394
395
397 """
398 Remove any zProperties defined in the ZenPack
399
400 @param app: ZenPack
401 @type app: ZenPack object
402 """
403 for name, value, pType in self.packZProperties:
404 app.zport.dmd.Devices._delProperty(name)
405
406
408 """
409 Delete all objects in the zenPackPersistence catalog that are
410 associated with this zenpack.
411
412 @param app: ZenPack
413 @type app: ZenPack object
414 """
415 objects = self.getCatalogedObjects()
416 for o in objects:
417 parent = aq_parent(o)
418 if parent:
419 parent._delObject(o.id)
420
421
429
430
432 """
433 Edit a ZenPack object
434 """
435
436 if self.isEggPack():
437
438 newDeps = {}
439 depNames = REQUEST.get('dependencies', [])
440 if not isinstance(depNames, list):
441 depNames = [depNames]
442 newDeps = {}
443 for depName in depNames:
444 fieldName = 'version_%s' % depName
445 vers = REQUEST.get(fieldName, '').strip()
446 if vers and vers[0] in string.digits:
447 vers = '==' + vers
448 try:
449 req = pkg_resources.Requirement.parse(depName + vers)
450 except ValueError:
451 messaging.IMessageSender(self).sendToBrowser(
452 'Error',
453 '%s is not a valid version specification.' % vers,
454 priority=messaging.WARNING
455 )
456 return self.callZenScreen(REQUEST)
457 zp = self.dmd.ZenPackManager.packs._getOb(depName, None)
458 if not zp:
459 messaging.IMessageSender(self).sendToBrowser(
460 'Error',
461 '%s is not installed.' % depName,
462 priority=messaging.WARNING
463 )
464 return self.callZenScreen(REQUEST)
465 if not req.__contains__(zp.version):
466 messaging.IMessageSender(self).sendToBrowser(
467 'Error',
468 ('The required version for %s (%s) ' % (depName, vers) +
469 'does not match the installed version (%s).' %
470 zp.version),
471 priority=messaging.WARNING
472 )
473 return self.callZenScreen(REQUEST)
474 newDeps[depName] = vers
475 REQUEST.form[fieldName] = vers
476 self.dependencies = newDeps
477
478
479 compatZenossVers = REQUEST.form['compatZenossVers'] or ''
480 if compatZenossVers:
481 if compatZenossVers[0] in string.digits:
482 compatZenossVers = '==' + compatZenossVers
483 try:
484 req = pkg_resources.Requirement.parse(
485 'zenoss%s' % compatZenossVers)
486 except ValueError:
487 messaging.IMessageSender(self).sendToBrowser(
488 'Error',
489 ('%s is not a valid version specification for Zenoss.'
490 % compatZenossVers),
491 priority=messaging.WARNING
492 )
493 if not req.__contains__(ZENOSS_VERSION):
494 messaging.IMessageSender(self).sendToBrowser(
495 'Error',
496 ('%s does not match this version of Zenoss (%s).' %
497 (compatZenossVers, ZENOSS_VERSION)),
498 priority=messaging.WARNING
499 )
500 return self.callZenScreen(REQUEST)
501 REQUEST.form['compatZenossVers'] = compatZenossVers
502
503 if 'Select or specify your own' in REQUEST.get('license', ''):
504 REQUEST.form['license'] = ''
505
506 result = ZenModelRM.zmanage_editProperties(self, REQUEST, redirect,
507 audit=False)
508 audit('UI.ZenPack.Edit',
509 self.id,
510 data_=REQUEST.form,
511 skipFields_=('redirect',
512 'zenScreenName',
513 'zmanage_editProperties'))
514
515 if self.isEggPack():
516 self.writeSetupValues()
517 self.writeLicense()
518 self.buildEggInfo()
519 return result
520
521
534
535
550
551
552 security.declareProtected(ZEN_MANAGE_DMD, 'manage_exportPack')
554 """
555 Export the ZenPack to the /export directory
556
557 @param download: download to client's desktop? ('yes' vs anything else)
558 @type download: string
559 @type download: string
560 @param REQUEST: Zope REQUEST object
561 @type REQUEST: Zope REQUEST object
562 @todo: make this more modular
563 @todo: add better XML headers
564 """
565 if not self.isDevelopment():
566 msg = 'Only ZenPacks installed in development mode can be exported.'
567 if REQUEST:
568 messaging.IMessageSender(self).sendToBrowser(
569 'Error', msg, priority=messaging.WARNING)
570 return self.callZenScreen(REQUEST)
571 raise ZenPackDevelopmentModeExeption(msg)
572
573 from StringIO import StringIO
574 xml = StringIO()
575
576
577
578 xml.write("""<?xml version="1.0"?>\n""")
579 xml.write("<objects>\n")
580
581 packables = eliminateDuplicates(self.packables())
582 for obj in packables:
583
584 xml.write('<!-- %r -->\n' % (obj.getPrimaryPath(),))
585 obj.exportXml(xml,['devices','networks','pack'],True)
586 xml.write("</objects>\n")
587 path = self.path('objects')
588 if not os.path.isdir(path):
589 os.mkdir(path, 0750)
590 objects = file(os.path.join(path, 'objects.xml'), 'w')
591 objects.write(xml.getvalue())
592 objects.close()
593
594
595 path = self.path('skins')
596 if not os.path.isdir(path):
597 os.makedirs(path, 0750)
598
599
600 init = self.path('__init__.py')
601 if not os.path.isfile(init):
602 fp = file(init, 'w')
603 fp.write(
604 '''
605 import Globals
606 from Products.CMFCore.DirectoryView import registerDirectory
607 registerDirectory("skins", globals())
608 ''')
609 fp.close()
610
611 if self.isEggPack():
612
613 exportDir = zenPath('export')
614 if not os.path.isdir(exportDir):
615 os.makedirs(exportDir, 0750)
616 eggPath = self.eggPath()
617 os.chdir(eggPath)
618 if os.path.isdir(os.path.join(eggPath, 'dist')):
619 os.system('rm -rf dist/*')
620 p = subprocess.Popen('python setup.py bdist_egg',
621 stderr=sys.stderr,
622 shell=True,
623 cwd=eggPath)
624 p.wait()
625 os.system('cp dist/* %s' % exportDir)
626 exportFileName = self.eggName()
627 else:
628
629 about = self.path(CONFIG_FILE)
630 values = {}
631 parser = ConfigParser.SafeConfigParser()
632 if os.path.isfile(about):
633 try:
634 parser.read(about)
635 values = dict(parser.items(CONFIG_SECTION_ABOUT))
636 except ConfigParser.Error:
637 pass
638 current = [(p['id'], str(getattr(self, p['id'], '') or ''))
639 for p in self._properties]
640 values.update(dict(current))
641 if not parser.has_section(CONFIG_SECTION_ABOUT):
642 parser.add_section(CONFIG_SECTION_ABOUT)
643 for key, value in values.items():
644 parser.set(CONFIG_SECTION_ABOUT, key, value)
645 fp = file(about, 'w')
646 try:
647 parser.write(fp)
648 finally:
649 fp.close()
650
651 path = zenPath('export')
652 if not os.path.isdir(path):
653 os.makedirs(path, 0750)
654 from zipfile import ZipFile, ZIP_DEFLATED
655 zipFilePath = os.path.join(path, '%s.zip' % self.id)
656 zf = ZipFile(zipFilePath, 'w', ZIP_DEFLATED)
657 base = zenPath('Products')
658 for p, ds, fd in os.walk(self.path()):
659 if p.split('/')[-1].startswith('.'): continue
660 for f in fd:
661 if f.startswith('.'): continue
662 if f.endswith('.pyc'): continue
663 filename = os.path.join(p, f)
664 zf.write(filename, filename[len(base)+1:])
665 ds[:] = [d for d in ds if d[0] != '.']
666 zf.close()
667 exportFileName = '%s.zip' % self.id
668
669 audit('UI.ZenPack.Export', exportFileName)
670
671 if REQUEST:
672 dlLink = '- <a target="_blank" href="%s/manage_download">' \
673 'Download Zenpack</a>' % self.absolute_url_path()
674 messaging.IMessageSender(self).sendToBrowser(
675 'ZenPack Exported',
676 'ZenPack exported to $ZENHOME/export/%s %s' %
677 (exportFileName, dlLink if download == 'yes' else ''),
678 messaging.CRITICAL if download == 'yes' else messaging.INFO
679 )
680 return self.callZenScreen(REQUEST)
681
682 return exportFileName
683
685 """
686 Download the already exported zenpack from $ZENHOME/export
687
688 @param REQUEST: Zope REQUEST object
689 @type REQUEST: Zope REQUEST object
690 """
691 if self.isEggPack():
692 filename = self.eggName()
693 else:
694 filename = '%s.zip' % self.id
695 path = os.path.join(zenPath('export'), filename)
696 if os.path.isfile(path):
697 REQUEST.RESPONSE.setHeader('content-type', 'application/zip')
698 REQUEST.RESPONSE.setHeader('content-disposition',
699 'attachment; filename=%s' %
700 filename)
701 zf = file(path, 'r')
702 try:
703 REQUEST.RESPONSE.write(zf.read())
704 finally:
705 zf.close()
706 else:
707 messaging.IMessageSender(self).sendToBrowser(
708 'Error',
709 'An error has occurred. The ZenPack could not be exported.',
710 priority=messaging.WARNING
711 )
712 return self.callZenScreen(REQUEST)
713
714
716 dsClasses = []
717 for path, dirs, files in os.walk(self.path(name)):
718 dirs[:] = [d for d in dirs if not d.startswith('.')]
719 for f in files:
720 if not f.startswith('.') \
721 and f.endswith('.py') \
722 and not f == '__init__.py':
723 subPath = path[len(self.path()):]
724 parts = subPath.strip('/').split('/')
725 parts.append(f[:f.rfind('.')])
726 modName = '.'.join([self.moduleName()] + parts)
727 dsClasses.append(importClass(modName))
728 return dsClasses
729
732
735
737 """
738 Get the filenames of a ZenPack exclude .svn, .pyc and .xml files
739 """
740 filenames = []
741 for root, dirs, files in os.walk(self.path()):
742 if root.find('.svn') == -1:
743 for f in files:
744 if not f.endswith('.pyc') \
745 and not f.endswith('.xml'):
746 filenames.append('%s/%s' % (root, f))
747 return filenames
748
749
751 """
752 Return a list of daemons in the daemon subdirectory that should be
753 stopped/started before/after an install or an upgrade of the zenpack.
754 """
755 daemonsDir = os.path.join(self.path(), 'daemons')
756 if os.path.isdir(daemonsDir):
757 daemons = [f for f in os.listdir(daemonsDir)
758 if os.path.isfile(os.path.join(daemonsDir,f))]
759 else:
760 daemons = []
761 return daemons
762
763
765 """
766 Stop all the daemons provided by this pack.
767 Called before an upgrade or a removal of the pack.
768 """
769 return
770 for d in self.getDaemonNames():
771 self.About.doDaemonAction(d, 'stop')
772
773
775 """
776 Start all the daemons provided by this pack.
777 Called after an upgrade or an install of the pack.
778 """
779 return
780 for d in self.getDaemonNames():
781 self.About.doDaemonAction(d, 'start')
782
783
785 """
786 Restart all the daemons provided by this pack.
787 Called after an upgrade or an install of the pack.
788 """
789 for d in self.getDaemonNames():
790 self.About.doDaemonAction(d, 'restart')
791
792
793 - def path(self, *parts):
794 """
795 Return the path to the ZenPack module.
796 It would be convenient to store the module name/path in the zenpack
797 object, however this would make things more complicated when the
798 name of the package under ZenPacks changed on us (do to a user edit.)
799 """
800 if self.isEggPack():
801 module = self.getModule()
802 return os.path.join(module.__path__[0], *[p.strip('/') for p in parts])
803 return zenPath('Products', self.id, *parts)
804
805
807 """
808 Return True if
809 1) the pack is an old-style ZenPack (not a Python egg)
810 or
811 2) the pack is a Python egg and is a source install (includes a
812 setup.py file)
813
814 Returns False otherwise.
815 """
816 if self.isEggPack():
817 return os.path.isfile(self.eggPath('setup.py'))
818 return True
819
820
822 """
823 Return True if this is a new-style (egg) zenpack, false otherwise
824 """
825 return self.eggPack
826
827
829 """
830 Return the importable dotted module name for this zenpack.
831 """
832 if self.isEggPack():
833 name = self.getModule().__name__
834 else:
835 name = 'Products.%s' % self.id
836 return name
837
838
840 """
841 Helper to install configuration files under "etc/".
842 Typcially they should not be deleted on uninstall.
843 """
844 filepath = 'etc/' + filename
845 self.installFile(filepath, overwriteIfExists=False)
846 self.installFile(filepath, filepath + '.example', overwriteIfExists=True)
847
848
850 """
851 Helper to install script files under "bin/".
852 Typically they should be deleted on uninstall with removeBinFile().
853 """
854 filepath = 'bin/' + filename
855 self.installFile(filepath, overwriteIfExists=True, symLink=True)
856
857
859 filepath = 'bin/' + filename
860 self.removeFile(filepath)
861
862
863 - def installFile(self, relativePath, relativeDestPath=None,
864 overwriteIfExists=True, symLink=False):
865 """
866 Install a file from this zenpack to ZENHOME upon installation.
867 By default, relativePath is for the zenpack and its ZENHOME destination.
868 Returns True if installed, False/Exception otherwise.
869
870 Example: self.installFile('etc/myzenpack.data')
871 """
872 srcPath = self.path(relativePath)
873 destPath = zenPath(relativePath) if relativeDestPath is None \
874 else zenPath(relativeDestPath)
875
876 if not overwriteIfExists and os.path.lexists(destPath):
877 return False
878 if not os.path.exists(srcPath):
879 raise ZenPackException('Missing source file %s' % srcPath)
880 if os.path.lexists(destPath):
881 os.remove(destPath)
882
883
884 if os.path.lexists(destPath):
885 raise ZenPackException('Failed to remove file %s' % destPath)
886 if symLink:
887 os.symlink(srcPath, destPath)
888 else:
889 shutil.copy2(srcPath, destPath)
890 if not os.path.lexists(destPath):
891 raise ZenPackException('Failed to write file %s' % destPath)
892 return True
893
894
895 - def removeFile(self, relativePath, mustSucceed=False):
896 """
897 Remove a file installed in ZENHOME by this zenpack, if it exists.
898
899 Example: self.removeFile('etc/myzenpack.data')
900 """
901 destPath = zenPath(relativePath)
902 if os.path.lexists(destPath):
903 os.remove(destPath)
904 if mustSucceed and os.path.lexists(destPath):
905 raise ZenPackException('Failed to remove file %s' % destPath)
906
907
908
909
910
911
912
913
915 """
916 Write appropriate values to the setup.py file
917 """
918 import Products.ZenUtils.ZenPackCmd as ZenPackCmd
919 if not self.isEggPack():
920 raise ZenPackException('Calling writeSetupValues on non-egg zenpack.')
921
922
923 packages = []
924 parts = self.id.split('.')
925 for i in range(len(parts)):
926 packages.append('.'.join(parts[:i+1]))
927
928 attrs = dict(
929 NAME=self.id,
930 VERSION=self.version,
931 AUTHOR=self.author,
932 LICENSE=self.license,
933 NAMESPACE_PACKAGES=packages[:-1],
934 PACKAGES = packages,
935 INSTALL_REQUIRES = ['%s%s' % d for d in self.dependencies.items()],
936 COMPAT_ZENOSS_VERS = self.compatZenossVers,
937 PREV_ZENPACK_NAME = self.prevZenPackName,
938 )
939 ZenPackCmd.WriteSetup(self.eggPath('setup.py'), attrs)
940
942 """
943 Write LICENSE.txt file based on the ZenPack's license attribute.
944 """
945 if self.license not in ExampleLicenses.LICENSES:
946 return
947
948 license_text = ExampleLicenses.LICENSES[self.license] % {
949 'year': datetime.date.today().year,
950 'author': self.author and self.author or '<AUTHOR>',
951 }
952
953 with open(self.path('LICENSE.txt'), 'w') as license_file:
954 license_file.write(license_text.lstrip('\n'))
955
957 """
958 Rebuild the egg info to update dependencies, etc
959 """
960 p = subprocess.Popen('python setup.py egg_info',
961 stderr=sys.stderr,
962 shell=True,
963 cwd=self.eggPath())
964 p.wait()
965
966
968 """
969 Return the distribution that provides this zenpack
970 """
971 if not self.isEggPack():
972 raise ZenPackException('Calling getDistribution on non-egg zenpack.')
973 return pkg_resources.get_distribution(self.id)
974
975
976 - def getEntryPoint(self):
977 """
978 Return a tuple of (packName, packEntry) that comes from the
979 distribution entry map for zenoss.zenopacks.
980 """
981 if not self.isEggPack():
982 raise ZenPackException('Calling getEntryPoints on non-egg zenpack.')
983 dist = self.getDistribution()
984 entryMap = pkg_resources.get_entry_map(dist, 'zenoss.zenpacks')
985 if not entryMap or len(entryMap) > 1:
986 raise ZenPackException('A ZenPack egg must contain exactly one'
987 ' zenoss.zenpacks entry point. This egg appears to contain'
988 ' %s such entry points.' % len(entryMap))
989 packName, packEntry = entryMap.items()[0]
990 return (packName, packEntry)
991
992
994 """
995 Get the loaded module from the given entry point. if not packEntry
996 then retrieve it.
997 """
998 if not self.isEggPack():
999 raise ZenPackException('Calling getModule on non-egg zenpack.')
1000 _, packEntry = self.getEntryPoint()
1001 return packEntry.load()
1002
1003
1005 """
1006 Return the path to the egg supplying this zenpack
1007 """
1008 if not self.isEggPack():
1009 raise ZenPackException('Calling eggPath on non-egg zenpack.')
1010 d = self.getDistribution()
1011 return os.path.join(d.location, *[p.strip('/') for p in parts])
1012
1013
1019
1020
1022 """
1023 Return True if the egg itself should be deleted when this ZenPack
1024 is removed from Zenoss.
1025 If the ZenPack code resides in $ZENHOME/ZenPacks then it is
1026 deleted, otherwise it is not.
1027 """
1028 eggPath = self.eggPath()
1029 oneFolderUp = eggPath[:eggPath.rfind('/')]
1030 if oneFolderUp == zenPath('ZenPacks'):
1031 delete = True
1032 else:
1033 delete = False
1034 return delete
1035
1036
1038 """
1039 Return the name of submodule of zenpacks that contains this zenpack.
1040 """
1041 if not self.isEggPack():
1042 raise ZenPackException('Calling getPackageName on a non-egg '
1043 'zenpack')
1044 modName = self.moduleName()
1045 return modName.split('.')[1]
1046
1047
1049 """
1050 Return a list of installed zenpacks that could be listed as
1051 dependencies for this zenpack
1052 """
1053 result = []
1054 for zp in self.dmd.ZenPackManager.packs():
1055 try:
1056 if zp.id != self.id and zp.isEggPack():
1057 result.append(zp)
1058 except AttributeError:
1059 pass
1060 return result
1061
1062
1064 """
1065 Return True if the egg is located in the ZenPacks directory,
1066 False otherwise.
1067 """
1068 zpDir = zenPath('ZenPacks') + '/'
1069 eggDir = self.eggPath()
1070 return eggDir.startswith(zpDir)
1071
1072
1074 """
1075 Make sure that the ZenPack can be instantiated and that it
1076 is physically present on the filesystem.
1077 """
1078
1079
1080
1081
1082
1083 try:
1084 if not os.path.isdir(self.path()):
1085 return True
1086 except pkg_resources.DistributionNotFound:
1087 return True
1088
1089
1090 try:
1091 unused = self.packables()
1092 except Exception:
1093 return True
1094
1095 return False
1096
1099
1100
1101
1102
1103
1104
1105 ZenPackBase = ZenPack
1106
1107 InitializeClass(ZenPack)
1108