def testEngineFactorySingletonPattern(self): # Call monitorsdb.engineFactory() engine = monitorsdb.engineFactory() # Call monitorsdb.engineFactory() again and assert singleton engine2 = monitorsdb.engineFactory() self.assertIs(engine2, engine) # Call monitorsdb.engineFactory() in different process, assert new # instance originalEngineId = id(engine) engine3 = multiprocessing.Pool(processes=1).apply(_forkedEngineId) self.assertNotEqual(id(engine3), originalEngineId)
def addErrorFlag(table, uid, name=None): """ Adds issue to table. :param table: A database table :type table: sqlalchemy.schema.Table :param uid: a unique issue id :type uid: string :param name: name of issue :type name: string """ name = name if name is not None else uid ins = table.insert().prefix_with("IGNORE", dialect="mysql").values( uid=uid, name=name, should_report=False) monitorsdb.engineFactory().execute(ins) g_logger.debug("Added new issue flag for %s", name)
def testTransientErrorRetryDecorator(self): # Setup proxy. We'll patch config later, so we need to cache the values # so that the original proxy may be restarted with the original params config = monitorsdb.MonitorsDbConfig() originalHost = config.get("repository", "host") originalPort = config.getint("repository", "port") def _startProxy(): p = startProxy(originalHost, originalPort, 6033) p.next() return p proxy = _startProxy() self.addCleanup(proxy.send, "kill") # Patch monitorsdb config with local proxy with ConfigAttributePatch( config.CONFIG_NAME, config.baseConfigDir, (("repository", "host", "127.0.0.1"), ("repository", "port", "6033"))): # Force refresh of engine singleton monitorsdb._EngineSingleton._pid = None engine = monitorsdb.engineFactory() # First, make sure valid query returns expected results res = engine.execute("select 1") self.assertEqual(res.scalar(), 1) @monitorsdb.retryOnTransientErrors def _killProxyTryRestartProxyAndTryAgain(n=[]): if not n: # Kill the proxy on first attempt proxy.send("kill") proxy.next() try: engine.execute("select 1") self.fail("Proxy did not terminate as expected...") except sqlalchemy.exc.OperationalError: pass n.append(None) elif len(n) == 1: # Restore proxy in second attempt newProxy = _startProxy() self.addCleanup(newProxy.send, "kill") n.append(None) res = engine.execute("select 2") return res # Try again w/ retry decorator result = _killProxyTryRestartProxyAndTryAgain() # Verify that the expected value is eventually returned self.assertEqual(result.scalar(), 2)
def _dispatchNotificationWithTransactionAwareRetries(): with monitorsdb.engineFactory().begin() as conn: """ Wrap dispatchNotification() in a transaction, in case there is an error that prevents the notification being dispatched. In such a case we DO NOT want to save the notification so that it may be re-attempted later """ if cls._recordNotification(conn, checkFn, excType, excValue): dispatchNotification(self, checkFn, excType, excValue, excTraceback)
def testTransientErrorRetryDecorator(self): # Setup proxy. We'll patch config later, so we need to cache the values # so that the original proxy may be restarted with the original params config = monitorsdb.MonitorsDbConfig() originalHost = config.get("repository", "host") originalPort = config.getint("repository", "port") def _startProxy(): p = startProxy(originalHost, originalPort, 6033) p.next() return p proxy = _startProxy() self.addCleanup(proxy.send, "kill") # Patch monitorsdb config with local proxy with ConfigAttributePatch(config.CONFIG_NAME, config.baseConfigDir, (("repository", "host", "127.0.0.1"), ("repository", "port", "6033"))): # Force refresh of engine singleton monitorsdb._EngineSingleton._pid = None engine = monitorsdb.engineFactory() # First, make sure valid query returns expected results res = engine.execute("select 1") self.assertEqual(res.scalar(), 1) @monitorsdb.retryOnTransientErrors def _killProxyTryRestartProxyAndTryAgain(n=[]): if not n: # Kill the proxy on first attempt proxy.send("kill") proxy.next() try: engine.execute("select 1") self.fail("Proxy did not terminate as expected...") except sqlalchemy.exc.OperationalError: pass n.append(None) elif len(n) == 1: # Restore proxy in second attempt newProxy = _startProxy() self.addCleanup(newProxy.send, "kill") n.append(None) res = engine.execute("select 2") return res # Try again w/ retry decorator result = _killProxyTryRestartProxyAndTryAgain() # Verify that the expected value is eventually returned self.assertEqual(result.scalar(), 2)
def removeErrorFlag(table, uid): """ Removes issue with uid from table. :param table: A database table :type table: sqlalchemy.schema.Table :param uid: a unique issue id :type uid: string """ cmd = table.delete().where(table.c.uid == uid) result = monitorsdb.engineFactory().execute(cmd) if result.rowcount > 0: g_logger.debug("Removed issue flag: %s", uid)
def testEngineFactorySingletonPattern(self, sqlalchemyMock): # Explicitly spec out sqlalchemy.create_engine() firstCall = Mock(spec_set=sqlalchemy.engine.base.Engine) secondCall = Mock(spec_set=sqlalchemy.engine.base.Engine) sqlalchemyMock.create_engine.side_effect = iter([firstCall, secondCall]) # Call monitorsdb.engineFactory() engine = monitorsdb.engineFactory() self.assertIs(engine, firstCall) # Call monitorsdb.engineFactory() again and assert singleton engine2 = monitorsdb.engineFactory() self.assertIs(engine2, firstCall) self.assertEqual(sqlalchemyMock.create_engine.call_count, 1) # Call monitorsdb.engineFactory() in different process, assert new # instance with patch("taurus_monitoring.monitorsdb.os", autospec=True) as osMock: osMock.getpid.return_value = monitorsdb._EngineSingleton._pid + 1 engine3 = monitorsdb.engineFactory() self.assertTrue(engine.dispose.called) self.assertIs(engine3, secondCall)
def testEngineFactorySingletonPattern(self, sqlalchemyMock): # Explicitly spec out sqlalchemy.create_engine() firstCall = Mock(spec_set=sqlalchemy.engine.base.Engine) secondCall = Mock(spec_set=sqlalchemy.engine.base.Engine) sqlalchemyMock.create_engine.side_effect = iter( [firstCall, secondCall]) # Call monitorsdb.engineFactory() engine = monitorsdb.engineFactory() self.assertIs(engine, firstCall) # Call monitorsdb.engineFactory() again and assert singleton engine2 = monitorsdb.engineFactory() self.assertIs(engine2, firstCall) self.assertEqual(sqlalchemyMock.create_engine.call_count, 1) # Call monitorsdb.engineFactory() in different process, assert new # instance with patch("taurus_monitoring.monitorsdb.os", autospec=True) as osMock: osMock.getpid.return_value = monitorsdb._EngineSingleton._pid + 1 engine3 = monitorsdb.engineFactory() self.assertTrue(engine.dispose.called) self.assertIs(engine3, secondCall)
def containsErrorFlag(table, uid): """ Checks whether issue(s) with specified uid is(are) present in specified table. :param table: A database table :type table: sqlalchemy.schema.Table :param uid: a unique issue id :type uid: string :returns: True is there exist any row(s) in the table having specified uid, False otherwise :rtype: Boolean """ sel = table.select().where(table.c.uid == uid) issues = monitorsdb.engineFactory().execute(sel).fetchall() return len(issues) > 0
def clearAllNotificationsInteractiveConsoleScriptEntryPoint(cls): """ Interactive utility for manually clearing out all notifications. Meant to be used as a console script entry point, defined in setup.py. User will be prompted with a stern warning to delete notifications, and required to enter "Yes-" followed by a random integer. """ engine = monitorsdb.engineFactory() expectedAnswer = "Yes-%s" % (random.randint(1, 30),) answer = raw_input( "Attention! You are about to do something irreversible, and potentially" " dangerous.\n" "\n" "To back out immediately without making any changes, feel free to type " "anything but \"{}\" in the prompt below, and press return.\n" "\n" "Should you choose to continue, all notifications in the DATABASE \"{}\"" "will be PERMANENTLY DELETED.\n" "\n" "Are you sure you want to continue? " .format(expectedAnswer, engine)) if answer.strip() != expectedAnswer: print "Aborting - Wise choice, my friend. Bye." return # Disable `No value passed for parameter 'dml' in function call # (no-value-for-parameter)` warnings # pylint: disable=E1120 cmd = monitorDispatcherTable.delete() @monitorsdb.retryOnTransientErrors def _executeWithRetries(): monitorsdb.engineFactory().execute(cmd) _executeWithRetries() print "Notifications deleted."
def _executeWithRetries(): monitorsdb.engineFactory().execute(cmd)
def _forkedEngineId(): """ Get engine and return id. Needs to be in global namespace for multiprocessing.Pool().apply() to work properly """ return id(monitorsdb.engineFactory())