diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py2/twisted/application/service.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py2/twisted/application/service.py')
-rw-r--r-- | contrib/python/Twisted/py2/twisted/application/service.py | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py2/twisted/application/service.py b/contrib/python/Twisted/py2/twisted/application/service.py new file mode 100644 index 0000000000..c6da29bf61 --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/application/service.py @@ -0,0 +1,424 @@ +# -*- test-case-name: twisted.application.test.test_service -*- +# Copyright (c) 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 __future__ import absolute_import, division + +from zope.interface import implementer, Interface, Attribute + +from twisted.persisted import sob +from twisted.python.reflect import namedAny +from twisted.python import components +from twisted.python._oldstyle import _oldStyle +from twisted.internet import defer +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 + L{twisted.python.usage.Options} instance) of configuration + options to desired configuration values. + """ + + + +@implementer(IPlugin, IServiceMaker) +class ServiceMaker(object): + """ + Utility class to simplify the definition of L{IServiceMaker} plugins. + """ + 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. + """ + + name = Attribute( + "A C{str} which is the name of the service or C{None}.") + + running = Attribute( + "A C{boolean} which indicates whether the service is running.") + + parent = Attribute( + "An C{IServiceCollection} which is the parent or C{None}.") + + 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. This method is responsible for setting + the C{parent} attribute on this service (the child 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<defer.Deferred>} + @return: a L{Deferred<defer.Deferred>} which is triggered when the + service has finished shutting down. If shutting down is immediate, + a value can be returned (usually, L{None}). + """ + + def startService(): + """ + Start the service. + """ + + def stopService(): + """ + Stop the service. + + @rtype: L{Deferred<defer.Deferred>} + @return: a L{Deferred<defer.Deferred>} which is triggered when the + service has finished shutting down. If shutting down is immediate, + a value can be returned (usually, L{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. + """ + + + +@implementer(IService) +class Service(object): + """ + Base class for services. + + Most services should inherit from this class. It handles the + book-keeping responsibilities of starting and stopping, as well + as not serializing this book-keeping information. + """ + + running = 0 + name = None + parent = None + + def __getstate__(self): + dict = self.__dict__.copy() + if "running" in dict: + 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. + + Only implementations of L{IService.setServiceParent} should use this + method. + + @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<defer.Deferred>} + @return: a L{Deferred<defer.Deferred>} which is triggered when the + service has finished shutting down. If shutting down is immediate, + a value can be returned (usually, L{None}). + """ + + + +@implementer(IServiceCollection) +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. + """ + + 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 service.name in self.namedServices: + 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. + """ + processName = Attribute( + """ + A C{str} giving the name the process should have in ps (or L{None} + to leave the name alone). + """) + + uid = Attribute( + """ + An C{int} giving the user id as which the process should run (or + L{None} to leave the UID alone). + """) + + gid = Attribute( + """ + An C{int} giving the group id as which the process should run (or + L{None} to leave the GID alone). + """) + + + +@implementer(IProcess) +@_oldStyle +class Process: + """ + Process running parameters. + + Sets up uid/gid in the constructor, and has a default + of L{None} as C{processName}. + """ + 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 L{None}, no attempt will be made to change the UID. + + @param gid: The group ID as whom to execute the process. If + this is L{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() + availableComponents = [MultiService(), Process(uid, gid), + sob.Persistent(ret, name)] + + for comp in availableComponents: + 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') + else: + application = sob.load(filename, kind) + return application + + +__all__ = ['IServiceMaker', 'IService', 'Service', + 'IServiceCollection', 'MultiService', + 'IProcess', 'Process', 'Application', 'loadApplication'] |