summaryrefslogtreecommitdiff
path: root/vendor/Twisted-10.0.0/twisted/application/service.py
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/Twisted-10.0.0/twisted/application/service.py')
-rw-r--r--vendor/Twisted-10.0.0/twisted/application/service.py398
1 files changed, 398 insertions, 0 deletions
diff --git a/vendor/Twisted-10.0.0/twisted/application/service.py b/vendor/Twisted-10.0.0/twisted/application/service.py
new file mode 100644
index 0000000000..16cd938ffb
--- /dev/null
+++ b/vendor/Twisted-10.0.0/twisted/application/service.py
@@ -0,0 +1,398 @@
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+
+"""
+Service architecture for Twisted.
+
+Services are arranged in a hierarchy. At the leafs of the hierarchy,
+the services which actually interact with the outside world are started.
+Services can be named or anonymous -- usually, they will be named if
+there is need to access them through the hierarchy (from a parent or
+a sibling).
+
+Maintainer: Moshe Zadka
+"""
+
+from zope.interface import implements, Interface, Attribute
+
+from twisted.python.reflect import namedAny
+from twisted.python import components
+from twisted.internet import defer
+from twisted.persisted import sob
+from twisted.plugin import IPlugin
+
+class IServiceMaker(Interface):
+ """
+ An object which can be used to construct services in a flexible
+ way.
+
+ This interface should most often be implemented along with
+ L{twisted.plugin.IPlugin}, and will most often be used by the
+ 'twistd' command.
+ """
+ tapname = Attribute(
+ "A short string naming this Twisted plugin, for example 'web' or "
+ "'pencil'. This name will be used as the subcommand of 'twistd'.")
+
+ description = Attribute(
+ "A brief summary of the features provided by this "
+ "Twisted application plugin.")
+
+ options = Attribute(
+ "A C{twisted.python.usage.Options} subclass defining the"
+ "configuration options for this application.")
+
+
+ def makeService(options):
+ """
+ Create and return an object providing
+ L{twisted.application.service.IService}.
+
+ @param options: A mapping (typically a C{dict} or
+ C{twisted.python.usage.Options} instance) of configuration
+ options to desired configuration values.
+ """
+
+
+
+class ServiceMaker(object):
+ """
+ Utility class to simplify the definition of L{IServiceMaker} plugins.
+ """
+ implements(IPlugin, IServiceMaker)
+
+ def __init__(self, name, module, description, tapname):
+ self.name = name
+ self.module = module
+ self.description = description
+ self.tapname = tapname
+
+
+ def options():
+ def get(self):
+ return namedAny(self.module).Options
+ return get,
+ options = property(*options())
+
+
+ def makeService():
+ def get(self):
+ return namedAny(self.module).makeService
+ return get,
+ makeService = property(*makeService())
+
+
+
+class IService(Interface):
+ """
+ A service.
+
+ Run start-up and shut-down code at the appropriate times.
+
+ @type name: C{string}
+ @ivar name: The name of the service (or None)
+ @type running: C{boolean}
+ @ivar running: Whether the service is running.
+ """
+
+ def setName(name):
+ """
+ Set the name of the service.
+
+ @type name: C{str}
+ @raise RuntimeError: Raised if the service already has a parent.
+ """
+
+ def setServiceParent(parent):
+ """
+ Set the parent of the service.
+
+ @type parent: L{IServiceCollection}
+ @raise RuntimeError: Raised if the service already has a parent
+ or if the service has a name and the parent already has a child
+ by that name.
+ """
+
+ def disownServiceParent():
+ """
+ Use this API to remove an L{IService} from an L{IServiceCollection}.
+
+ This method is used symmetrically with L{setServiceParent} in that it
+ sets the C{parent} attribute on the child.
+
+ @rtype: L{Deferred}
+ @return: a L{Deferred} which is triggered when the service has
+ finished shutting down. If shutting down is immediate,
+ a value can be returned (usually, C{None}).
+ """
+
+ def startService():
+ """
+ Start the service.
+ """
+
+ def stopService():
+ """
+ Stop the service.
+
+ @rtype: L{Deferred}
+ @return: a L{Deferred} which is triggered when the service has
+ finished shutting down. If shutting down is immediate, a
+ value can be returned (usually, C{None}).
+ """
+
+ def privilegedStartService():
+ """
+ Do preparation work for starting the service.
+
+ Here things which should be done before changing directory,
+ root or shedding privileges are done.
+ """
+
+
+class Service:
+ """
+ Base class for services.
+
+ Most services should inherit from this class. It handles the
+ book-keeping reponsibilities of starting and stopping, as well
+ as not serializing this book-keeping information.
+ """
+
+ implements(IService)
+
+ running = 0
+ name = None
+ parent = None
+
+ def __getstate__(self):
+ dict = self.__dict__.copy()
+ if dict.has_key("running"):
+ del dict['running']
+ return dict
+
+ def setName(self, name):
+ if self.parent is not None:
+ raise RuntimeError("cannot change name when parent exists")
+ self.name = name
+
+ def setServiceParent(self, parent):
+ if self.parent is not None:
+ self.disownServiceParent()
+ parent = IServiceCollection(parent, parent)
+ self.parent = parent
+ self.parent.addService(self)
+
+ def disownServiceParent(self):
+ d = self.parent.removeService(self)
+ self.parent = None
+ return d
+
+ def privilegedStartService(self):
+ pass
+
+ def startService(self):
+ self.running = 1
+
+ def stopService(self):
+ self.running = 0
+
+
+
+class IServiceCollection(Interface):
+ """
+ Collection of services.
+
+ Contain several services, and manage their start-up/shut-down.
+ Services can be accessed by name if they have a name, and it
+ is always possible to iterate over them.
+ """
+
+ def getServiceNamed(name):
+ """
+ Get the child service with a given name.
+
+ @type name: C{str}
+ @rtype: L{IService}
+ @raise KeyError: Raised if the service has no child with the
+ given name.
+ """
+
+ def __iter__():
+ """
+ Get an iterator over all child services.
+ """
+
+ def addService(service):
+ """
+ Add a child service.
+
+ @type service: L{IService}
+ @raise RuntimeError: Raised if the service has a child with
+ the given name.
+ """
+
+ def removeService(service):
+ """
+ Remove a child service.
+
+ Only implementations of L{IService.disownServiceParent} should
+ use this method.
+
+ @type service: L{IService}
+ @raise ValueError: Raised if the given service is not a child.
+ @rtype: L{Deferred}
+ @return: a L{Deferred} which is triggered when the service has
+ finished shutting down. If shutting down is immediate, a
+ value can be returned (usually, C{None}).
+ """
+
+
+
+class MultiService(Service):
+ """
+ Straightforward Service Container.
+
+ Hold a collection of services, and manage them in a simplistic
+ way. No service will wait for another, but this object itself
+ will not finish shutting down until all of its child services
+ will finish.
+ """
+
+ implements(IServiceCollection)
+
+ def __init__(self):
+ self.services = []
+ self.namedServices = {}
+ self.parent = None
+
+ def privilegedStartService(self):
+ Service.privilegedStartService(self)
+ for service in self:
+ service.privilegedStartService()
+
+ def startService(self):
+ Service.startService(self)
+ for service in self:
+ service.startService()
+
+ def stopService(self):
+ Service.stopService(self)
+ l = []
+ services = list(self)
+ services.reverse()
+ for service in services:
+ l.append(defer.maybeDeferred(service.stopService))
+ return defer.DeferredList(l)
+
+ def getServiceNamed(self, name):
+ return self.namedServices[name]
+
+ def __iter__(self):
+ return iter(self.services)
+
+ def addService(self, service):
+ if service.name is not None:
+ if self.namedServices.has_key(service.name):
+ raise RuntimeError("cannot have two services with same name"
+ " '%s'" % service.name)
+ self.namedServices[service.name] = service
+ self.services.append(service)
+ if self.running:
+ # It may be too late for that, but we will do our best
+ service.privilegedStartService()
+ service.startService()
+
+ def removeService(self, service):
+ if service.name:
+ del self.namedServices[service.name]
+ self.services.remove(service)
+ if self.running:
+ # Returning this so as not to lose information from the
+ # MultiService.stopService deferred.
+ return service.stopService()
+ else:
+ return None
+
+
+
+class IProcess(Interface):
+ """
+ Process running parameters.
+
+ Represents parameters for how processes should be run.
+
+ @ivar processName: the name the process should have in ps (or C{None})
+ @type processName: C{str}
+ @ivar uid: the user-id the process should run under.
+ @type uid: C{int}
+ @ivar gid: the group-id the process should run under.
+ @type gid: C{int}
+ """
+
+
+class Process:
+ """
+ Process running parameters.
+
+ Sets up uid/gid in the constructor, and has a default
+ of C{None} as C{processName}.
+ """
+ implements(IProcess)
+ processName = None
+
+ def __init__(self, uid=None, gid=None):
+ """
+ Set uid and gid.
+
+ @param uid: The user ID as whom to execute the process. If
+ this is C{None}, no attempt will be made to change the UID.
+
+ @param gid: The group ID as whom to execute the process. If
+ this is C{None}, no attempt will be made to change the GID.
+ """
+ self.uid = uid
+ self.gid = gid
+
+
+def Application(name, uid=None, gid=None):
+ """
+ Return a compound class.
+
+ Return an object supporting the L{IService}, L{IServiceCollection},
+ L{IProcess} and L{sob.IPersistable} interfaces, with the given
+ parameters. Always access the return value by explicit casting to
+ one of the interfaces.
+ """
+ ret = components.Componentized()
+ for comp in (MultiService(), sob.Persistent(ret, name), Process(uid, gid)):
+ ret.addComponent(comp, ignoreClass=1)
+ IService(ret).setName(name)
+ return ret
+
+
+
+def loadApplication(filename, kind, passphrase=None):
+ """
+ Load Application from a given file.
+
+ The serialization format it was saved in should be given as
+ C{kind}, and is one of C{pickle}, C{source}, C{xml} or C{python}. If
+ C{passphrase} is given, the application was encrypted with the
+ given passphrase.
+
+ @type filename: C{str}
+ @type kind: C{str}
+ @type passphrase: C{str}
+ """
+ if kind == 'python':
+ application = sob.loadValueFromFile(filename, 'application', passphrase)
+ else:
+ application = sob.load(filename, kind, passphrase)
+ return application
+
+
+__all__ = ['IServiceMaker', 'IService', 'Service',
+ 'IServiceCollection', 'MultiService',
+ 'IProcess', 'Process', 'Application', 'loadApplication']