def testRemoveNoCurrentServiceId(self): moduleName = "Zenpacks.zenoss.Test" services = _services + [_MockService('me', 'hub1', [moduleName])] client = _MockControlPlaneClient(services=services) with setControlPlaneClient(client): ZenPack("id").removeServices(moduleName) self.assertEquals(client.deleted, [])
def testConfigMap(self): tag = 'myZenpack' client = _MockControlPlaneClient(services=_services) fileDict = { "service.json": { 'servicePath': '/', 'serviceDefinition': { 'Id': 'svc', 'ConfigFiles': { '/opt/zenoss/etc/service.conf': {}, '/opt/zenoss/etc/other.conf': {} } } }, } configMap = { '/opt/zenoss/etc/service.conf': "foobar", '/opt/zenoss/etc/other.conf': "boofar" } client = _MockControlPlaneClient(services=_services) with setControlPlaneClient(client), setCurrentService( 'zope'), setBuiltinOpen(fileDict): ZenPack('id').installServicesFromFiles(fileDict.keys(), [configMap], tag) self.assertEquals(len(fileDict), len(client.added)) for i, j in ((i[0], json.loads(i[1])) for i in client.added): for key, val in configMap.iteritems(): self.assertEquals(j['ConfigFiles'][key]['Content'], val)
def testAddNoCurrentServiceId(self): context = _MockServiceMigrationContext() client = _MockControlPlaneClient(services=_services) service = json.dumps(_MockService('id'), cls=_MockServiceEncoder) with setControlPlaneClient(client), setServiceMigrationContext( context): ZenPack("id").installServiceDefinitions(service, "/hub") self.assertEquals(context.added, [])
def testRemoveServices(self): tag = 'MyZenPack' services = _services + [ _MockService('alpha', 'zenoss', [tag]), _MockService('beta', 'hub1', [tag]), ] expected = ['alpha', 'beta'] client = _MockControlPlaneClient(services=services) with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").removeServices(tag) self.assertEquals(sorted(client.deleted), sorted(expected))
def testAddSingleService(self): client = _MockControlPlaneClient(services=_services) service = _MockService('id', 'pid') service.poolId = 'not_default' service = json.dumps(service, cls=_MockServiceEncoder) with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").installServiceDefinitions(service, "/hub") self.assertEquals(len(client.added), 1) parent, added = client.added[0][0], json.loads(client.added[0][1]) self.assertEquals(added['Id'], 'id') self.assertEquals(parent, 'hub1')
def testStopServices(self): tag = 'MyZenPack' services = _services + [ _MockService('alpha', 'zenoss', [tag]), _MockService('beta', 'hub1', [tag]), ] expected = ['alpha', 'beta'] client = _MockControlPlaneClient(services=services) with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").doServiceAction(tag, 'stop') self.assertEquals(sorted(client.stopped), sorted(expected))
def testNestedInstall(self): client = _MockControlPlaneClient(services=_services) services = [ json.dumps(_MockService(i), cls=_MockServiceEncoder) for i in ('svc1', 'root', 'svc2') ] paths = ['/=ROOT', '/', '/=ROOT'] with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").installServiceDefinitions(services, paths) # Confirm that parent is installed before children self.assertEquals(len(client.added), len(paths)) for i, v in enumerate(('root', 'svc', 'svc')): svc = json.loads(client.added[i][1]) self.assertIn(v, svc['Id'])
def testAddMultipleServices(self): client = _MockControlPlaneClient(services=_services) services = [ json.dumps(_MockService(i), cls=_MockServiceEncoder) for i in ('id1', 'id2') ] paths = ['/', '/hub'] with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").installServiceDefinitions(services, paths) self.assertEquals(len(client.added), 2) added = [(i[0], json.loads(i[1])) for i in client.added] self.assertEquals(added[0][1]['Id'], 'id1') self.assertEquals(added[0][0], 'zenoss') self.assertEquals(added[1][1]['Id'], 'id2') self.assertEquals(added[1][0], 'hub1')
def testNestedInstall(self): context = _MockServiceMigrationContext() client = _MockControlPlaneClient(services=_services) services = [ json.dumps(_MockService(i), cls=_MockServiceEncoder) for i in ('svc1', 'root', 'svc2') ] paths = ['/=ROOT', '/', '/=ROOT'] with setControlPlaneClient(client), setCurrentService( 'zope'), setServiceMigrationContext(context): ZenPack("id").installServiceDefinitions(services, paths) root = json.loads(context.added[0][1]) self.assertEquals(root["Name"], "ROOT") self.assertIn("SVC1", [s["Name"] for s in root["Services"]]) self.assertIn("SVC2", [s["Name"] for s in root["Services"]])
def testInstallFromFiles(self): tag = 'myZenpack' E_KEY = 'expectedParentId' # for this test only - associates path with service P_KEY = 'servicePath' # key defining path at which to install service D_KEY = 'serviceDefinition' # key defining service to be installed I_KEY = 'Id' # key defining ID N_KEY = 'Name' # key defining Name # Mock the filesystem - maps path->json file contents fileDict = dict( a={ P_KEY: '/', D_KEY: { E_KEY: 'zenoss', I_KEY: 'a', N_KEY: 'A' } }, b={ P_KEY: '/hub', D_KEY: { E_KEY: 'hub1', I_KEY: 'b', N_KEY: 'B' } }, c={ P_KEY: '/hub', D_KEY: { E_KEY: 'hub1', I_KEY: 'c', N_KEY: 'C' } }, ) context = _MockServiceMigrationContext() client = _MockControlPlaneClient(services=_services) with setControlPlaneClient(client), setCurrentService( 'zope'), setServiceMigrationContext(context): z = ZenPack('id') z._loadServiceDefinition = createMockLoadServiceDefinitions( fileDict) z.installServicesFromFiles(fileDict.keys(), [{}] * len(fileDict.keys()), tag) self.assertEquals(len(fileDict), len(context.added)) for i, j in ((i[0], json.loads(i[1])) for i in context.added): self.assertEquals(i, j[E_KEY])
def testNestedRemove(self): tag = 'zp' _services = [ _MockService('zenoss', '', []), _MockService('zope', 'zenoss', ['daemon']), _MockService('svc1', 'root', [tag]), _MockService('root', 'zenoss', [tag]), _MockService('svc2', 'root', [tag]), ] client = _MockControlPlaneClient(services=_services) with setControlPlaneClient(client), setCurrentService('zope'): ZenPack("id").removeServices(tag) expected = ['root', 'svc1', 'svc2'] self.assertEquals(sorted(client.deleted), sorted(expected)) # Confirm child services deleted before parent self.assertLess(client.deleted.index('svc1'), client.deleted.index('root')) self.assertLess(client.deleted.index('svc2'), client.deleted.index('root'))
def install(self, packName): zp = None # We wrap our try in a try to abort our tansaction, but make sure we # unpause applyDataMap functionality try: try: # hide uncatalog error messages since they do not do any harm log = logging.getLogger('Zope.ZCatalog') oldLevel = log.getEffectiveLevel() log.setLevel(HIGHER_THAN_CRITICAL) zp = self.dmd.ZenPackManager.packs._getOb(packName) self.log.info('Upgrading %s', packName) self.dmd.startPauseADM() zp.upgrade(self.app) except AttributeError: try: module = __import__('Products.' + packName, globals(), {}, ['']) zp = module.ZenPack(packName) except (ImportError, AttributeError) as ex: self.log.debug( "Unable to find custom ZenPack (%s), defaulting to generic ZenPack", ex ) zp = ZenPack(packName) self.dmd.ZenPackManager.packs._setObject(packName, zp) zp = self.dmd.ZenPackManager.packs._getOb(packName) zp.install(self.app) finally: log.setLevel(oldLevel) if zp: for required in zp.requires: try: self.dmd.ZenPackManager.packs._getOb(required) except Exception: self.log.error( "Pack %s requires pack %s: not installing", packName, required ) return except Exception: transaction.abort() finally: self.dmd.stopPauseADM()
def install(self, packName): zp = None try: # hide uncatalog error messages since they do not do any harm log = logging.getLogger('Zope.ZCatalog') oldLevel = log.getEffectiveLevel() log.setLevel(HIGHER_THAN_CRITICAL) zp = self.dmd.ZenPackManager.packs._getOb(packName) self.log.info('Upgrading %s' % packName) zp.upgrade(self.app) except AttributeError: try: module = __import__('Products.' + packName, globals(), {}, ['']) zp = module.ZenPack(packName) except (ImportError, AttributeError), ex: self.log.debug( "Unable to find custom ZenPack (%s), " "defaulting to generic ZenPack", ex) zp = ZenPack(packName) self.dmd.ZenPackManager.packs._setObject(packName, zp) zp = self.dmd.ZenPackManager.packs._getOb(packName) zp.install(self.app)
def testAddMultipleServicesRelative(self): context = _MockServiceMigrationContext() client = _MockControlPlaneClient(services=_services) services = [ json.dumps(dict(Name=n, Tags=[t])) for n, t in zip( ["a", "b", "c", "d", "e"], ["1", "2", "3", "4", "5"]) ] paths = ["/hub/..", "/=ZOPE", "/=ZOPE/=b", "/=ZOPE/=b/=c", "/hub/../1"] with setControlPlaneClient(client), setCurrentService( 'zope'), setServiceMigrationContext(context): ZenPack("id").installServiceDefinitions(services, paths) self.assertEquals( [json.loads(a[1]) for a in context.added], [{ "Services": [{ "Services": [], "Name": "e", "Tags": ["5"] }], "Name": "a", "Tags": ["1"] }, { "Services": [{ "Services": [{ "Services": [], "Name": "d", "Tags": ["4"] }], "Name": "c", "Tags": ["3"] }], "Name": "b", "Tags": ["2"] }])
def transactional_actions(): # Instantiate ZenPack entryMap = pkg_resources.get_entry_map(dist, ZENPACK_ENTRY_POINT) if not entryMap or len(entryMap) > 1: raise ZenPackException( 'A ZenPack egg must contain exactly one' ' zenoss.zenpacks entry point. This egg appears to contain' ' %s such entry points.' % len(entryMap)) packName, packEntry = entryMap.items()[0] runExternalZenpack = True #if zenpack with same name exists we can't load both modules #installing new egg zenpack will be done in a sub process existing = dmd.ZenPackManager.packs._getOb(packName, None) if existing: log.info("Previous ZenPack exists with same name %s" % packName) if filesOnly or not existing: #running files only or zenpack by same name doesn't already exists # so no need to install the zenpack in an external process runExternalZenpack = False module = packEntry.load() if hasattr(module, 'ZenPack'): zenPack = module.ZenPack(packName) else: zenPack = ZenPack(packName) zenPack.eggPack = True CopyMetaDataToZenPackObject(dist, zenPack) if filesOnly: for loader in (ZPL.ZPLDaemons(), ZPL.ZPLBin(), ZPL.ZPLLibExec()): loader.load(zenPack, None) if fromUI and not zenPack.installableFromUI: raise ZenPackException( "This ZenPack cannot be installed through the UI.") if not filesOnly: # Look for an installed ZenPack to be upgraded. In this case # upgraded means that it is removed before the new one is installed # but that its objects are not removed and the packables are # copied to the new instance. existing = dmd.ZenPackManager.packs._getOb(packName, None) if not existing and zenPack.prevZenPackName: existing = dmd.ZenPackManager.packs._getOb( zenPack.prevZenPackName, None) deferFileDeletion = False packables = [] upgradingFrom = None if existing: upgradingFrom = existing.version for p in existing.packables(): packables.append(p) existing.packables.removeRelation(p) if existing.isEggPack(): forceNoFileDeletion = existing.eggPath() == dist.location RemoveZenPack(dmd, existing.id, skipDepsCheck=True, leaveObjects=True, forceNoFileDeletion=forceNoFileDeletion, uninstallEgg=False) else: # Don't delete files, might still be needed for # migrate scripts to be run below. deferFileDeletion = True oldzenpack.RemoveZenPack(dmd, existing.id, skipDepsCheck=True, leaveObjects=True, deleteFiles=False) if runExternalZenpack or forceRunExternal: log.info("installing zenpack %s; launching process" % packName) cmd = [binPath('zenpack')] if link: cmd += ["--link"] cmd += ["--install", eggPath] if upgradingFrom: cmd += ['--previousversion', upgradingFrom] if fromUI: cmd += ["--fromui"] cmdStr = " ".join(cmd) log.debug("launching sub process command: %s" % cmdStr) p = subprocess.Popen(cmdStr, shell=True) out, err = p.communicate() p.wait() if p.returncode: raise ZenPackException( 'Error installing the egg (%s): %s' % (p.returncode, err)) dmd._p_jar.sync() else: dmd.ZenPackManager.packs._setObject(packName, zenPack) zenPack = dmd.ZenPackManager.packs._getOb(packName) #hack because ZenPack.install is overridden by a lot of zenpacks #so we can't change the signature of install to take the #previousVerison zenPack.prevZenPackVersion = previousVersion zenPack.install(dmd) zenPack.prevZenPackVersion = None try: zenPack = dmd.ZenPackManager.packs._getOb(packName) for p in packables: pId = p.getPrimaryId() try: # make sure packable still exists; could be deleted by a # migrate getObjByPath(dmd, pId) log.debug("adding packable relation for id %s", pId) zenPack.packables.addRelation(p) except (KeyError, zExceptions.NotFound): log.debug('did not find packable %s', pId) except AttributeError, e: # If this happens in the child process or during the non-upgrade # flow, reraise the exception if not runExternalZenpack: raise # This specific error will occur when the version of the ZenPack # being installed subclasses Products.ZenModel.ZenPack, but the # previous version of the ZenPack did not. if str(e) == "'ZenPack' object has no attribute '__of__'": zenPack = ZenPack(packName) else: # This is the signature error of class-loading issues # during zenpack upgrade. The final state should be okay, # except that modified packables may be lost. message = "There has been an error during the post-" + \ "installation steps for the zenpack %s. In " + \ "most cases, no further action is required. If " + \ "issues persist, please reinstall this zenpack." message = message % packName log.warning(message) raise NonCriticalInstallError(message) cleanupSkins(dmd) return zenPack, deferFileDeletion, existing