celeryd_detach.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import os
  2. import sys
  3. from optparse import OptionParser, BadOptionError, make_option as Option
  4. from celery import __version__
  5. from celery.platforms import create_daemon_context
  6. OPTION_LIST = (
  7. Option('-f', '--logfile', default=None,
  8. action="store", dest="logfile",
  9. help="Path to the logfile"),
  10. Option('--pidfile', default="celeryd.pid",
  11. action="store", dest="pidfile",
  12. help="Path to the pidfile."),
  13. Option('--uid', default=None,
  14. action="store", dest="uid",
  15. help="Effective user id to run as when detached."),
  16. Option('--gid', default=None,
  17. action="store", dest="gid",
  18. help="Effective group id to run as when detached."),
  19. Option('--umask', default=0,
  20. action="store", type="int", dest="umask",
  21. help="Umask of the process when detached."),
  22. Option('--workdir', default=None,
  23. action="store", dest="working_directory",
  24. help="Directory to change to when detached."),
  25. Option('--chroot', default=None,
  26. action="store", dest="chroot_directory",
  27. help="Change root directory to this path when detached."),
  28. )
  29. class detached(object):
  30. def __init__(self, path, argv, logfile=None, pidfile=None, uid=None,
  31. gid=None, umask=0, working_directory=None, chroot_directory=None):
  32. self.path = path
  33. self.argv = argv
  34. self.logfile = logfile
  35. self.pidfile = pidfile
  36. self.uid = uid
  37. self.gid = gid
  38. self.umask = umask
  39. self.working_directory = working_directory
  40. self.chroot_directory = chroot_directory
  41. def start(self):
  42. context, on_stop = create_daemon_context(
  43. logfile=self.logfile,
  44. pidfile=self.pidfile,
  45. uid=self.uid,
  46. gid=self.gid,
  47. umask=self.umask,
  48. working_directory=self.working_directory,
  49. chroot_directory=self.chroot_directory)
  50. context.open()
  51. try:
  52. os.execv(self.path, [self.path] + self.argv)
  53. finally:
  54. on_stop()
  55. class PartialOptionParser(OptionParser):
  56. def __init__(self, *args, **kwargs):
  57. self.leftovers = []
  58. OptionParser.__init__(self, *args, **kwargs)
  59. def _process_long_opt(self, rargs, values):
  60. arg = rargs.pop(0)
  61. if "=" in arg:
  62. opt, next_arg = arg.split("=", 1)
  63. rargs.insert(0, next_arg)
  64. had_explicit_value = True
  65. else:
  66. opt = arg
  67. had_explicit_value = False
  68. try:
  69. opt = self._match_long_opt(opt)
  70. option = self._long_opt.get(opt)
  71. except BadOptionError:
  72. option = None
  73. if option:
  74. if option.takes_value():
  75. nargs = option.nargs
  76. if len(rargs) < nargs:
  77. if nargs == 1:
  78. self.error(_("%s option requires an argument") % opt)
  79. else:
  80. self.error(_("%s option requires %d arguments")
  81. % (opt, nargs))
  82. elif nargs == 1:
  83. value = rargs.pop(0)
  84. else:
  85. value = tuple(rargs[0:nargs])
  86. del rargs[0:nargs]
  87. elif had_explicit_value:
  88. self.error(_("%s option does not take a value") % opt)
  89. else:
  90. value = None
  91. option.process(opt, value, values, self)
  92. else:
  93. self.leftovers.append(arg)
  94. def _process_short_opts(self, rargs, values):
  95. arg = rargs[0]
  96. try:
  97. OptionParser._process_short_opts(self, rargs, values)
  98. except BadOptionError:
  99. self.leftovers.append(arg)
  100. if rargs and not rargs[0][0] == "-":
  101. self.leftovers.append(rargs.pop(0))
  102. class detached_celeryd(object):
  103. option_list = OPTION_LIST
  104. usage = "%%prog [options] [celeryd options]"
  105. version = __version__
  106. description = ("Detaches Celery worker nodes. See `celeryd --help` "
  107. "for the list of supported worker arguments.")
  108. command = sys.executable
  109. execv_path = sys.executable
  110. execv_argv = ["-m", "celery.bin.celeryd"]
  111. def Parser(self, prog_name):
  112. return PartialOptionParser(prog=prog_name,
  113. option_list=self.option_list,
  114. usage=self.usage,
  115. description=self.description,
  116. version=self.version)
  117. def parse_options(self, prog_name, argv):
  118. parser = self.Parser(prog_name)
  119. options, values = parser.parse_args(argv)
  120. if options.logfile:
  121. parser.leftovers.append("--logfile=%s" % (options.logfile, ))
  122. if options.pidfile:
  123. parser.leftovers.append("--pidfile=%s" % (options.pidfile, ))
  124. print("LEFTOVERS: %r" % (parser.leftovers, ))
  125. return options, values, parser.leftovers
  126. def execute_from_commandline(self, argv=None):
  127. if argv is None:
  128. argv = sys.argv
  129. prog_name = os.path.basename(argv[0])
  130. options, values, leftovers = self.parse_options(prog_name, argv[1:])
  131. detached(path=self.execv_path,
  132. argv=self.execv_argv + leftovers,
  133. **vars(options)).start()
  134. def main():
  135. detached_celeryd().execute_from_commandline()
  136. if __name__ == "__main__":
  137. main()