systemd.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. # -*- test-case-name: twisted.python.test.test_systemd -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Integration with systemd.
  6. Currently only the minimum APIs necessary for using systemd's socket activation
  7. feature are supported.
  8. """
  9. from __future__ import division, absolute_import
  10. __all__ = ['ListenFDs']
  11. from os import getpid
  12. class ListenFDs(object):
  13. """
  14. L{ListenFDs} provides access to file descriptors inherited from systemd.
  15. Typically L{ListenFDs.fromEnvironment} should be used to construct a new
  16. instance of L{ListenFDs}.
  17. @cvar _START: File descriptors inherited from systemd are always
  18. consecutively numbered, with a fixed lowest "starting" descriptor. This
  19. gives the default starting descriptor. Since this must agree with the
  20. value systemd is using, it typically should not be overridden.
  21. @type _START: C{int}
  22. @ivar _descriptors: A C{list} of C{int} giving the descriptors which were
  23. inherited.
  24. """
  25. _START = 3
  26. def __init__(self, descriptors):
  27. """
  28. @param descriptors: The descriptors which will be returned from calls to
  29. C{inheritedDescriptors}.
  30. """
  31. self._descriptors = descriptors
  32. @classmethod
  33. def fromEnvironment(cls, environ=None, start=None):
  34. """
  35. @param environ: A dictionary-like object to inspect to discover
  36. inherited descriptors. By default, L{None}, indicating that the
  37. real process environment should be inspected. The default is
  38. suitable for typical usage.
  39. @param start: An integer giving the lowest value of an inherited
  40. descriptor systemd will give us. By default, L{None}, indicating
  41. the known correct (that is, in agreement with systemd) value will be
  42. used. The default is suitable for typical usage.
  43. @return: A new instance of C{cls} which can be used to look up the
  44. descriptors which have been inherited.
  45. """
  46. if environ is None:
  47. from os import environ
  48. if start is None:
  49. start = cls._START
  50. descriptors = []
  51. try:
  52. pid = int(environ['LISTEN_PID'])
  53. except (KeyError, ValueError):
  54. pass
  55. else:
  56. if pid == getpid():
  57. try:
  58. count = int(environ['LISTEN_FDS'])
  59. except (KeyError, ValueError):
  60. pass
  61. else:
  62. descriptors = range(start, start + count)
  63. del environ['LISTEN_PID'], environ['LISTEN_FDS']
  64. return cls(descriptors)
  65. def inheritedDescriptors(self):
  66. """
  67. @return: The configured list of descriptors.
  68. """
  69. return list(self._descriptors)