def setUp(self): self.runLoop = RunLoop.currentRunLoop() self.runLoop.waitBeforeCalling(60, self.timeout) self.timedOut = False self.tempdir = tempfile.mkdtemp('.apps') self.appBundlePath = os.path.join(self.tempdir, 'testapp') os.mkdir(self.appBundlePath) self.appConfPath = os.path.join(self.appBundlePath, 'app.conf') self.configTemplate = ''' <app> <!-- the worlds most boring app --> </app> ''' open(self.appConfPath,'w').write(self.configTemplate)
def setUp(self): self.delegate = Delegate() super(self.__class__,self).setUp() self.runLoop = RunLoop.currentRunLoop() # Wire URLProtocol URLHTTPProtocol.run_loop = RunLoop URLHTTPProtocol.assembled() URLProtocol.registerClass(URLHTTPProtocol) URLConnection.URLProtocol = URLProtocol URLCache.assembled() URLConnection.URLCache = URLCache URLConnection.runLoop = RunLoop # Wire RunLoop ls = LogService() ls.useStreamHandler(sys.stderr) RunLoop.log = ls.__binding__('RunLoop', RunLoop)
def setUp(self): super(self.__class__,self).setUp() self.runLoop = RunLoop.currentRunLoop() # Wire URLHTTPProtocol URLHTTPProtocol.LRProtocol = LineReceiverProtocol URLHTTPProtocol.portFactory = Port # Wire URLProtocol URLProtocol.registerClass(URLDataProtocol) URLProtocol.registerClass(URLHTTPProtocol) # Wire URLConnection URLConnection.URLProtocol = URLProtocol URLConnection.runLoop = RunLoop URLConnection.URLRequest = URLRequest # Wire RunLoop ls = LogService() ls.useStreamHandler(sys.stderr) RunLoop.log = ls.__binding__('RunLoop', RunLoop) XMLSchemaService.URLConnection = URLConnection self.XMLSchemaService = XMLSchemaService self.schema = None
def main(): """Used by ramblerapp, a script that is created automatically for us by setuptools, to load an appBundle into it's own process.""" import os,sys # Todo: this should really double fork (on posix platforms, not # sure about windows which doesn't have fork), I if you start appMan from the command line # and send it a ^C any sub app it starts also get's that ^C which # isn't what we want. from optparse import OptionParser parser = OptionParser() parser.add_option("-d", dest="daemonize", action="store_true", default=False, help="Run this process as a background daemon") parser.add_option("-v", dest="logLevel", action="count", default=0, help="Increase logging verbosity by one for each -v specified on the commandline") parser.add_option("-b", dest="breakAt", default=None, help="Use python debugger to break @ file:line, needs -f") parser.add_option("-o", action="append", dest="options", default=[], help='Set extension option -o "section:key=value"') (options, args) = parser.parse_args() # app's can be started using the ramblerapp shell command, in that # case the first argument must be the path to the application # bundle. If the name of the script isn't ramblerapp say it's # "foo" then we assume this is an application whose bundle is # under /usr/lib/Rambler/extensions. # Todo: come up with a better way to specify the rambler # extensions directory. Perhaps check home directories as well, # that might make development eaiser scriptname = os.path.basename(sys.argv[0]) appBundlePath=None if scriptname != "ramblerapp": # Depending on what platform we're on the scriptname could # either either foo or foo.exe, to add insult too injury the # scrip probably isn't installed in the bundle directory (the # directory containg the app.conf) file. So using setuptools # we'll first determine which egg this script came from, then # we'll use that to find the directory containing the app.conf # We may have more than one module that uses the same # appBundle, like appmanager and ramblercon, so consolt the # pkg_resources for that information. This only works if the script # wass installed as an egg 'console_script' for ep in pkg_resources.iter_entry_points('console_scripts',scriptname): # Note, asking for the '' filename only works on unzipped # packages. If I want to make ramblerapps out of eggs # we'll need to redesign the "Bundle" concept. Heck we # might be able to ditch Bundles in favor of eggs # alltogether.... # We may one or more scripts that appBundlePath = pkg_resources.resource_filename(ep.dist.project_name,'') # Warning: There could be more than one script of the same # name in setuptools database. Typically this means that # two different projects installed the same console_script # with the same name. Now the bad part is, who knows which # script is actually installed. break # if appBundlePath wasn't set, then the script name didn't # refer to a script installed by an egg. As a last ditch # effort and probably the most common case the scriptname # referes to a vanilla python package appBundlePath = appBundlePath or pkg_resources.resource_filename(os.path.basename(scriptname),'') elif len(args) < 1: print >> sys.stderr, "Please specify the application directory." return 1 else: appBundlePath = args[0] args = args[1:] # clear the options in sys.argv we didn't use and put the # positional ones back in. Right now we're donig this mostly for # ramblercon which is a commandline application. Might be nice to # have a way of getting positional arguments to a component that # doesn't involve munging the command line. #del sys.argv[1:] #sys.argv.extend(args) authoritativeOptions = None # close any open file handles, have to do this before we load the # app cause who knows what files we may open next if not options.daemonize: # keep stderr, stdin and stdout open startfd = 3 else: startfd = 3 # wonder if closing files is neccesary now that we don't fork.. import os try: maxfd = os.sysconf("SC_OPEN_MAX") except (AttributeError, ValueError): maxfd = 256 # default maximum for fd in range(startfd, maxfd): try: os.close(fd) except OSError: # ERROR (ignore) pass app = Application(appBundlePath, authoritativeOptions=authoritativeOptions) logService = app.lookup("LogService") level = logService.defaultLevel - (options.logLevel * 10) logService.setLevel(level) if not options.daemonize: logService.useStreamHandler(sys.stderr) else: # since we didn't pass anything in this should already be done for us logService.useSyslogHandler() pass try: app.load() except: app.log.exception("Exception encountred while loading as a subprocess") return 1 try: RunLoop.currentRunLoop().run() except: app.log.exception("Unhandled exception encuntered in runLoop") return 255 # if we didn't die with an exception, exit with a 0, no errors return 0
def __init__(self, appDir, authoritativeOptions = None, **defaultComps): self.appBundle = Bundle(appDir) self.configFile = self.appBundle.pathForResource('app.conf') self.status = Application.STOPPED self.digest = "" self.name = os.path.basename(os.path.abspath(appDir)) if not authoritativeOptions: authoritativeOptions = {} authoritativeOptions['application.name'] = self.name authoritativeOptions['application.path'] = os.path.abspath(appDir) authoritativeOptions['system.hostname'] = socket.gethostname() self.loadConfig() logService = defaultComps.get("LogService") if logService is None: # everybody needs logging, especally during devel. If one # isn't passed to us, set one up to go directly to syslog logService = LogService() logService.addData('app', self.name) logService.setFormat('[%(app)s:%(name)s:%(levelname)s] %(message)s') logService.useSyslogHandler() defaultComps["LogService"] = logService # load the module that adapts our logging to somthething that twisted deferred's and failuers likes defaultComps["StdioOnnaStick"] = StdioOnnaStick() defaultComps["ErrorFactory"] = ErrorFactory() # these two are sessions so we put their classe rather than # instances in componentRegistry defaultComps["RunLoop"] = RunLoop defaultComps["PortFactory"] = Port # our os signal handling, has to be as light weight as # possible. so any signal this app receives will be processed # by the sameRunLoop that started this app (hopefully you # don't have it bogged down running long synchronous tasks) self.mainRunLoop = RunLoop.currentRunLoop() self.componentRegistry = CompBinder() for compName, component in defaultComps.items(): self.componentRegistry.addComponent(compName, component) serviceRegistry = ServiceRegistry() # blehq, serviceRegistry needs the application name in order to # load services that have been configured by convention serviceRegistry.app_name = self.name serviceRegistry.app = self self.componentRegistry.addComponent("ServiceRegistry", serviceRegistry) # need to bind ServiceRegistry's before we can add the App as # a service. self.componentRegistry.bind() # Set up the config service with authorative options configService = ciConfigService() for option, value in authoritativeOptions.items(): configService.set_default(option, value) try: # todo, remove this crap afte we pull the last bits of corba/omniorb from Rambler from epo import ciIApplication, ciIConfigService # Register the application service so that we can be remotely managed serviceRegistry.addService("Application", self, ciIApplication, []) serviceRegistry.addService("ConfigService", configService, ciIConfigService, []) except ImportError: # corba isn't installed serviceRegistry.addService("Application", self, None, []) # Note: ConfigService is placed into the componentRegistry # via the service registry. Not sure why I did this. serviceRegistry.addService("ConfigService", configService, None, []) self.componentRegistry.bind()
except: # we died during shutdown, althought this should be # reported as a crash,we don't want a crash handler to try # and restart us, after all we died when we were stopping self.log.exception('Did not shutdown cleanly!') # Now that the components are offline, we'll tell the # Server that we're done, and then stop the RunLoop as # soon as the controller aknowledeges us self.setStatus(Application.STOPPED) elif status in (Application.STOPPED, Application.CRASHED): self.log.info("Shutdown Complete") RunLoop.currentRunLoop().stop() def onStatusError(self, failure, status): # Couldn't notify our controller, it could be temporarily # down, let's continue about our merry way. self.log.debug("%s got error %s while notifying controller of status %s," " continuing." % (self.name, failure.getErrorMessage(), status)) self.onStatusSent(None, status) def main(): """Used by ramblerapp, a script that is created automatically for us by setuptools, to load an appBundle into it's own process."""
def setUp(self): self.observed = False self.run_loop = RunLoop.currentRunLoop()
def timeout(self): # test took to long to complete, set a flag and stop the RunLoop self.timedOut = True RunLoop.currentRunLoop().stop()
def stopRunLoop(*args, **kw): if len(args) > 0 and hasattr(args[0], 'printTraceback'): args[0].printTraceback() # used to stop the runLoop from via a deffered object which usually calls back with one or more args RunLoop.currentRunLoop().stop()