base.py 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. _NOW = 1151365354
  2. _TIMEFORMAT = '%b %d %I:%M %p'
  3. class DummyOptions:
  4. make_pipes_error = None
  5. fork_error = None
  6. execv_error = None
  7. kill_error = None
  8. minfds = 5
  9. loglevel = 20
  10. def __init__(self):
  11. self.identifier = 'supervisor'
  12. self.childlogdir = '/tmp'
  13. self.uid = 999
  14. self.logger = self.getLogger()
  15. self.backofflimit = 10
  16. self.logfile = '/tmp/logfile'
  17. self.nocleanup = False
  18. self.strip_ansi = False
  19. self.pidhistory = {}
  20. self.process_group_configs = []
  21. self.nodaemon = False
  22. self.socket_map = {}
  23. self.mood = 1
  24. self.mustreopen = False
  25. self.realizeargs = None
  26. self.fds_cleaned_up = False
  27. self.rlimit_set = False
  28. self.setuid_called = False
  29. self.httpservers_opened = False
  30. self.signals_set = False
  31. self.daemonized = False
  32. self.make_logger_messages = None
  33. self.autochildlogdir_cleared = False
  34. self.cleaned_up = False
  35. self.pidfile_written = False
  36. self.directory = None
  37. self.waitpid_return = None, None
  38. self.kills = {}
  39. self._signal = None
  40. self.parent_pipes_closed = None
  41. self.child_pipes_closed = None
  42. self.forkpid = 0
  43. self.pgrp_set = None
  44. self.duped = {}
  45. self.written = {}
  46. self.fds_closed = []
  47. self._exitcode = None
  48. self.execve_called = False
  49. self.execv_args = None
  50. self.setuid_msg = None
  51. self.privsdropped = None
  52. self.logs_reopened = False
  53. self.environment_processed = False
  54. self.select_result = [], [], []
  55. self.select_error = None
  56. self.write_accept = None
  57. self.write_error = None
  58. self.tempfile_name = '/foo/bar'
  59. self.remove_error = None
  60. self.removed = []
  61. self.existing = []
  62. self.openreturn = None
  63. self.readfd_result = ''
  64. self.parse_warnings = []
  65. self.serverurl = 'http://localhost:9001'
  66. self.changed_directory = False
  67. self.chdir_error = None
  68. self.umaskset = None
  69. def getLogger(self, *args, **kw):
  70. logger = DummyLogger()
  71. logger.handlers = [DummyLogger()]
  72. logger.args = args, kw
  73. return logger
  74. def realize(self, args, **kw):
  75. self.realizeargs = args
  76. self.realizekw = kw
  77. def process_config(self, do_usage=True):
  78. pass
  79. def cleanup_fds(self):
  80. self.fds_cleaned_up = True
  81. def set_rlimits(self):
  82. self.rlimits_set = True
  83. return ['rlimits_set']
  84. def set_uid(self):
  85. self.setuid_called = True
  86. return 'setuid_called'
  87. def openhttpservers(self, supervisord):
  88. self.httpservers_opened = True
  89. def daemonize(self):
  90. self.daemonized = True
  91. def setsignals(self):
  92. self.signals_set = True
  93. def get_signal(self):
  94. return self._signal
  95. def get_socket_map(self):
  96. return self.socket_map
  97. def make_logger(self, critical_msgs, warn_msgs, info_msgs):
  98. self.make_logger_messages = critical_msgs, warn_msgs, info_msgs
  99. def clear_autochildlogdir(self):
  100. self.autochildlogdir_cleared = True
  101. def get_autochildlog_name(self, *ignored):
  102. return self.tempfile_name
  103. def cleanup(self):
  104. self.cleaned_up = True
  105. def write_pidfile(self):
  106. self.pidfile_written = True
  107. def waitpid(self):
  108. return self.waitpid_return
  109. def kill(self, pid, sig):
  110. if self.kill_error:
  111. raise OSError(self.kill_error)
  112. self.kills[pid] = sig
  113. def stat(self, filename):
  114. import os
  115. return os.stat(filename)
  116. def get_path(self):
  117. return ["/bin", "/usr/bin", "/usr/local/bin"]
  118. def get_pid(self):
  119. import os
  120. return os.getpid()
  121. def check_execv_args(self, filename, argv, st):
  122. if filename == '/bad/filename':
  123. from supervisor.options import NotFound
  124. raise NotFound('bad filename')
  125. def make_pipes(self, stderr=True):
  126. if self.make_pipes_error:
  127. raise OSError(self.make_pipes_error)
  128. pipes = {}
  129. pipes['child_stdin'], pipes['stdin'] = (3, 4)
  130. pipes['stdout'], pipes['child_stdout'] = (5, 6)
  131. if stderr:
  132. pipes['stderr'], pipes['child_stderr'] = (7, 8)
  133. else:
  134. pipes['stderr'], pipes['child_stderr'] = None, None
  135. return pipes
  136. def write(self, fd, chars):
  137. if self.write_error:
  138. raise OSError(self.write_error)
  139. if self.write_accept:
  140. chars = chars[self.write_accept]
  141. data = self.written.setdefault(fd, '')
  142. data += chars
  143. self.written[fd] = data
  144. return len(chars)
  145. def fork(self):
  146. if self.fork_error:
  147. raise OSError(self.fork_error)
  148. return self.forkpid
  149. def close_fd(self, fd):
  150. self.fds_closed.append(fd)
  151. def close_parent_pipes(self, pipes):
  152. self.parent_pipes_closed = pipes
  153. def close_child_pipes(self, pipes):
  154. self.child_pipes_closed = pipes
  155. def setpgrp(self):
  156. self.pgrp_set = True
  157. def dup2(self, frm, to):
  158. self.duped[frm] = to
  159. def _exit(self, code):
  160. self._exitcode = code
  161. def execve(self, filename, argv, environment):
  162. self.execve_called = True
  163. if self.execv_error:
  164. if self.execv_error == 1:
  165. raise OSError(self.execv_error)
  166. else:
  167. raise RuntimeError(self.execv_error)
  168. self.execv_args = (filename, argv)
  169. self.execv_environment = environment
  170. def dropPrivileges(self, uid):
  171. if self.setuid_msg:
  172. return self.setuid_msg
  173. self.privsdropped = uid
  174. def readfd(self, fd):
  175. return self.readfd_result
  176. def reopenlogs(self):
  177. self.logs_reopened = True
  178. def process_environment(self):
  179. self.environment_processed = True
  180. def mktempfile(self, prefix, suffix, dir):
  181. return self.tempfile_name
  182. def select(self, r, w, x, timeout):
  183. import select
  184. if self.select_error:
  185. raise select.error(self.select_error)
  186. return self.select_result
  187. def remove(self, path):
  188. import os
  189. if self.remove_error:
  190. raise os.error(self.remove_error)
  191. self.removed.append(path)
  192. def exists(self, path):
  193. if path in self.existing:
  194. return True
  195. return False
  196. def open(self, name, mode='r'):
  197. if self.openreturn:
  198. return self.openreturn
  199. return open(name, mode)
  200. def chdir(self, dir):
  201. if self.chdir_error:
  202. raise OSError(self.chdir_error)
  203. self.changed_directory = True
  204. def setumask(self, mask):
  205. self.umaskset = mask
  206. class DummyLogger:
  207. level = None
  208. def __init__(self):
  209. self.reopened = False
  210. self.removed = False
  211. self.closed = False
  212. self.data = []
  213. def info(self, msg, **kw):
  214. if kw:
  215. msg = msg % kw
  216. self.data.append(msg)
  217. warn = debug = critical = trace = error = blather = info
  218. def log(self, level, msg, **kw):
  219. if kw:
  220. msg = msg % kw
  221. self.data.append(msg)
  222. def addHandler(self, handler):
  223. pass
  224. def reopen(self):
  225. self.reopened = True
  226. def close(self):
  227. self.closed = True
  228. def remove(self):
  229. self.removed = True
  230. def flush(self):
  231. self.flushed = True
  232. def getvalue(self):
  233. return ''.join(self.data)
  234. class DummySupervisor:
  235. def __init__(self, options=None, state=None, process_groups=None):
  236. if options is None:
  237. self.options = DummyOptions()
  238. else:
  239. self.options = options
  240. if state is None:
  241. from supervisor.supervisord import SupervisorStates
  242. self.options.mood = SupervisorStates.RUNNING
  243. else:
  244. self.options.mood = state
  245. if process_groups is None:
  246. self.process_groups = {}
  247. else:
  248. self.process_groups = process_groups
  249. def get_state(self):
  250. return self.options.mood
  251. class DummySocket:
  252. bind_called = False
  253. bind_addr = None
  254. listen_called = False
  255. listen_backlog = None
  256. close_called = False
  257. def __init__(self, fd):
  258. self.fd = fd
  259. def fileno(self):
  260. return self.fd
  261. def bind(self, addr):
  262. self.bind_called = True
  263. self.bind_addr = addr
  264. def listen(self, backlog):
  265. self.listen_called = True
  266. self.listen_backlog = backlog
  267. def close(self):
  268. self.close_called = True
  269. def __str__(self):
  270. return 'dummy socket'
  271. class DummySocketConfig:
  272. def __init__(self, fd):
  273. self.fd = fd
  274. def addr(self):
  275. return 'dummy addr'
  276. def __eq__(self, other):
  277. return self.fd == other.fd
  278. def __ne__(self, other):
  279. return not self.__eq__(other)
  280. def create_and_bind(self):
  281. return DummySocket(self.fd)
  282. class DummySocketManager:
  283. def __init__(self, config, **kwargs):
  284. self._config = config
  285. def config(self):
  286. return self._config
  287. def get_socket(self):
  288. return DummySocket(self._config.fd)
  289. class DummyProcess:
  290. # Initial state; overridden by instance variables
  291. pid = 0 # Subprocess pid; 0 when not running
  292. laststart = 0 # Last time the subprocess was started; 0 if never
  293. laststop = 0 # Last time the subprocess was stopped; 0 if never
  294. delay = 0 # If nonzero, delay starting or killing until this time
  295. administrative_stop = 0 # true if the process has been stopped by an admin
  296. system_stop = 0 # true if the process has been stopped by the system
  297. killing = 0 # flag determining whether we are trying to kill this proc
  298. backoff = 0 # backoff counter (to backofflimit)
  299. waitstatus = None
  300. exitstatus = None
  301. pipes = None
  302. rpipes = None
  303. dispatchers = None
  304. stdout_logged = ''
  305. stderr_logged = ''
  306. spawnerr = None
  307. stdout_buffer = '' # buffer of characters from child stdout output to log
  308. stderr_buffer = '' # buffer of characters from child stderr output to log
  309. stdin_buffer = '' # buffer of characters to send to child process' stdin
  310. listener_state = None
  311. group = None
  312. def __init__(self, config, state=None):
  313. self.config = config
  314. self.logsremoved = False
  315. self.stop_called = False
  316. self.backoff_secs = None
  317. self.spawned = False
  318. if state is None:
  319. from supervisor.process import ProcessStates
  320. state = ProcessStates.RUNNING
  321. self.state = state
  322. self.error_at_clear = False
  323. self.killed_with = None
  324. self.drained = False
  325. self.stdout_buffer = ''
  326. self.stderr_buffer = ''
  327. self.stdout_logged = ''
  328. self.stderr_logged = ''
  329. self.stdin_buffer = ''
  330. self.pipes = {}
  331. self.rpipes = {}
  332. self.dispatchers = {}
  333. self.finished = None
  334. self.logs_reopened = False
  335. self.execv_arg_exception = None
  336. self.input_fd_drained = None
  337. self.output_fd_drained = None
  338. self.transitioned = False
  339. self.write_error = None
  340. def reopenlogs(self):
  341. self.logs_reopened = True
  342. def removelogs(self):
  343. if self.error_at_clear:
  344. raise IOError('whatever')
  345. self.logsremoved = True
  346. def get_state(self):
  347. return self.state
  348. def stop(self):
  349. self.stop_called = True
  350. self.killing = False
  351. from supervisor.process import ProcessStates
  352. self.state = ProcessStates.STOPPED
  353. def kill(self, signal):
  354. self.killed_with = signal
  355. def spawn(self):
  356. self.spawned = True
  357. from supervisor.process import ProcessStates
  358. self.state = ProcessStates.RUNNING
  359. def drain(self):
  360. self.drained = True
  361. def __cmp__(self, other):
  362. return cmp(self.config.priority, other.config.priority)
  363. def readable_fds(self):
  364. return []
  365. def record_output(self):
  366. self.stdout_logged += self.stdout_buffer
  367. self.stdout_buffer = ''
  368. self.stderr_logged += self.stderr_buffer
  369. self.stderr_buffer = ''
  370. def finish(self, pid, sts):
  371. self.finished = pid, sts
  372. def give_up(self):
  373. from supervisor.process import ProcessStates
  374. self.state = ProcessStates.FATAL
  375. def get_execv_args(self):
  376. if self.execv_arg_exception:
  377. raise self.execv_arg_exception('whatever')
  378. import shlex
  379. commandargs = shlex.split(self.config.command)
  380. program = commandargs[0]
  381. return program, commandargs
  382. def drain_output_fd(self, fd):
  383. self.output_fd_drained = fd
  384. def drain_input_fd(self, fd):
  385. self.input_fd_drained = fd
  386. def write(self, chars):
  387. if self.write_error:
  388. raise OSError(self.write_error)
  389. self.stdin_buffer += chars
  390. def transition(self):
  391. self.transitioned = True
  392. class DummyPConfig:
  393. def __init__(self, options, name, command, directory=None, umask=None,
  394. priority=999, autostart=True,
  395. autorestart=True, startsecs=10, startretries=999,
  396. uid=None, stdout_logfile=None, stdout_capture_maxbytes=0,
  397. stdout_events_enabled=False,
  398. stdout_logfile_backups=0, stdout_logfile_maxbytes=0,
  399. stderr_logfile=None, stderr_capture_maxbytes=0,
  400. stderr_events_enabled=False,
  401. stderr_logfile_backups=0, stderr_logfile_maxbytes=0,
  402. redirect_stderr=False,
  403. stopsignal=None, stopwaitsecs=10, stopasgroup=False, killasgroup=False,
  404. exitcodes=(0,2), environment=None, serverurl=None):
  405. self.options = options
  406. self.name = name
  407. self.command = command
  408. self.priority = priority
  409. self.autostart = autostart
  410. self.autorestart = autorestart
  411. self.startsecs = startsecs
  412. self.startretries = startretries
  413. self.uid = uid
  414. self.stdout_logfile = stdout_logfile
  415. self.stdout_capture_maxbytes = stdout_capture_maxbytes
  416. self.stdout_events_enabled = stdout_events_enabled
  417. self.stdout_logfile_backups = stdout_logfile_backups
  418. self.stdout_logfile_maxbytes = stdout_logfile_maxbytes
  419. self.stderr_logfile = stderr_logfile
  420. self.stderr_capture_maxbytes = stderr_capture_maxbytes
  421. self.stderr_events_enabled = stderr_events_enabled
  422. self.stderr_logfile_backups = stderr_logfile_backups
  423. self.stderr_logfile_maxbytes = stderr_logfile_maxbytes
  424. self.redirect_stderr = redirect_stderr
  425. if stopsignal is None:
  426. import signal
  427. stopsignal = signal.SIGTERM
  428. self.stopsignal = stopsignal
  429. self.stopwaitsecs = stopwaitsecs
  430. self.stopasgroup = stopasgroup
  431. self.killasgroup = killasgroup
  432. self.exitcodes = exitcodes
  433. self.environment = environment
  434. self.directory = directory
  435. self.umask = umask
  436. self.autochildlogs_created = False
  437. self.serverurl = serverurl
  438. def create_autochildlogs(self):
  439. self.autochildlogs_created = True
  440. def make_process(self, group=None):
  441. process = DummyProcess(self)
  442. process.group = group
  443. return process
  444. def make_dispatchers(self, proc):
  445. use_stderr = not self.redirect_stderr
  446. pipes = self.options.make_pipes(use_stderr)
  447. stdout_fd,stderr_fd,stdin_fd = (pipes['stdout'],pipes['stderr'],
  448. pipes['stdin'])
  449. dispatchers = {}
  450. if stdout_fd is not None:
  451. dispatchers[stdout_fd] = DummyDispatcher(readable=True)
  452. if stderr_fd is not None:
  453. dispatchers[stderr_fd] = DummyDispatcher(readable=True)
  454. if stdin_fd is not None:
  455. dispatchers[stdin_fd] = DummyDispatcher(writable=True)
  456. return dispatchers, pipes
  457. def makeExecutable(file, substitutions=None):
  458. import os
  459. import sys
  460. import tempfile
  461. if substitutions is None:
  462. substitutions = {}
  463. data = open(file).read()
  464. last = os.path.split(file)[1]
  465. substitutions['PYTHON'] = sys.executable
  466. for key in substitutions.keys():
  467. data = data.replace('<<%s>>' % key.upper(), substitutions[key])
  468. tmpnam = tempfile.mktemp(prefix=last)
  469. f = open(tmpnam, 'w')
  470. f.write(data)
  471. f.close()
  472. os.chmod(tmpnam, 0755)
  473. return tmpnam
  474. def makeSpew(unkillable=False):
  475. import os
  476. here = os.path.dirname(__file__)
  477. if not unkillable:
  478. return makeExecutable(os.path.join(here, 'fixtures/spew.py'))
  479. return makeExecutable(os.path.join(here, 'fixtures/unkillable_spew.py'))
  480. class DummyMedusaServerLogger:
  481. def __init__(self):
  482. self.logged = []
  483. def log(self, category, msg):
  484. self.logged.append((category, msg))
  485. class DummyMedusaServer:
  486. def __init__(self):
  487. self.logger = DummyMedusaServerLogger()
  488. class DummyMedusaChannel:
  489. def __init__(self):
  490. self.server = DummyMedusaServer()
  491. self.producer = None
  492. def push_with_producer(self, producer):
  493. self.producer = producer
  494. def close_when_done(self):
  495. pass
  496. def set_terminator(self, terminator):
  497. pass
  498. class DummyRequest:
  499. command = 'GET'
  500. _error = None
  501. _done = False
  502. version = '1.0'
  503. def __init__(self, path, params, query, fragment, env=None):
  504. self.args = path, params, query, fragment
  505. self.producers = []
  506. self.headers = {}
  507. self.header = []
  508. self.outgoing = []
  509. self.channel = DummyMedusaChannel()
  510. if env is None:
  511. self.env = {}
  512. else:
  513. self.env = env
  514. def split_uri(self):
  515. return self.args
  516. def error(self, code):
  517. self._error = code
  518. def push(self, producer):
  519. self.producers.append(producer)
  520. def __setitem__(self, header, value):
  521. self.headers[header] = value
  522. def has_key(self, header):
  523. return self.headers.has_key(header)
  524. def done(self):
  525. self._done = True
  526. def build_reply_header(self):
  527. return ''
  528. def log(self, *arg, **kw):
  529. pass
  530. def cgi_environment(self):
  531. return self.env
  532. def get_server_url(self):
  533. return 'http://example.com'
  534. class DummyRPCInterfaceFactory:
  535. def __init__(self, supervisord, **config):
  536. self.supervisord = supervisord
  537. self.config = config
  538. class DummyRPCServer:
  539. def __init__(self):
  540. self.supervisor = DummySupervisorRPCNamespace()
  541. self.system = DummySystemRPCNamespace()
  542. class DummySystemRPCNamespace:
  543. pass
  544. class DummySupervisorRPCNamespace:
  545. _restartable = True
  546. _restarted = False
  547. _shutdown = False
  548. _readlog_error = False
  549. from supervisor.process import ProcessStates
  550. all_process_info = [
  551. {
  552. 'name':'foo',
  553. 'group':'foo',
  554. 'pid':11,
  555. 'state':ProcessStates.RUNNING,
  556. 'statename':'RUNNING',
  557. 'start':_NOW - 100,
  558. 'stop':0,
  559. 'spawnerr':'',
  560. 'now':_NOW,
  561. 'description':'foo description',
  562. },
  563. {
  564. 'name':'bar',
  565. 'group':'bar',
  566. 'pid':12,
  567. 'state':ProcessStates.FATAL,
  568. 'statename':'FATAL',
  569. 'start':_NOW - 100,
  570. 'stop':_NOW - 50,
  571. 'spawnerr':'screwed',
  572. 'now':_NOW,
  573. 'description':'bar description',
  574. },
  575. {
  576. 'name':'baz_01',
  577. 'group':'baz',
  578. 'pid':13,
  579. 'state':ProcessStates.STOPPED,
  580. 'statename':'STOPPED',
  581. 'start':_NOW - 100,
  582. 'stop':_NOW - 25,
  583. 'spawnerr':'',
  584. 'now':_NOW,
  585. 'description':'baz description',
  586. },
  587. ]
  588. def getAPIVersion(self):
  589. return '3.0'
  590. getVersion = getAPIVersion # deprecated
  591. def getPID(self):
  592. return 42
  593. def readProcessStdoutLog(self, name, offset, length):
  594. from supervisor import xmlrpc
  595. import xmlrpclib
  596. if name == 'BAD_NAME':
  597. raise xmlrpclib.Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  598. elif name == 'FAILED':
  599. raise xmlrpclib.Fault(xmlrpc.Faults.FAILED, 'FAILED')
  600. elif name == 'NO_FILE':
  601. raise xmlrpclib.Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  602. a = 'output line\n' * 10
  603. return a[offset:]
  604. readProcessLog = readProcessStdoutLog
  605. readProcessStderrLog = readProcessStdoutLog
  606. def getAllProcessInfo(self):
  607. return self.all_process_info
  608. def getProcessInfo(self, name):
  609. from supervisor import xmlrpc
  610. import xmlrpclib
  611. for i in self.all_process_info:
  612. if i['name']==name:
  613. info=i
  614. return info
  615. if name == 'BAD_NAME':
  616. raise xmlrpclib.Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  617. if name == 'FAILED':
  618. raise xmlrpclib.Fault(xmlrpc.Faults.FAILED, 'FAILED')
  619. if name == 'NO_FILE':
  620. raise xmlrpclib.Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  621. def startProcess(self, name):
  622. from supervisor import xmlrpc
  623. from xmlrpclib import Fault
  624. if name == 'BAD_NAME:BAD_NAME':
  625. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME:BAD_NAME')
  626. if name == 'BAD_NAME':
  627. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  628. if name == 'NO_FILE':
  629. raise Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  630. if name == 'NOT_EXECUTABLE':
  631. raise Fault(xmlrpc.Faults.NOT_EXECUTABLE, 'NOT_EXECUTABLE')
  632. if name == 'ALREADY_STARTED':
  633. raise Fault(xmlrpc.Faults.ALREADY_STARTED, 'ALREADY_STARTED')
  634. if name == 'SPAWN_ERROR':
  635. raise Fault(xmlrpc.Faults.SPAWN_ERROR, 'SPAWN_ERROR')
  636. if name == 'ABNORMAL_TERMINATION':
  637. raise Fault(xmlrpc.Faults.ABNORMAL_TERMINATION,
  638. 'ABNORMAL_TERMINATION')
  639. return True
  640. def startProcessGroup(self, name):
  641. from supervisor import xmlrpc
  642. from xmlrpclib import Fault
  643. if name == 'BAD_NAME':
  644. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  645. return [
  646. {'name':'foo_00', 'group':'foo',
  647. 'status': xmlrpc.Faults.SUCCESS,
  648. 'description': 'OK'},
  649. {'name':'foo_01', 'group':'foo',
  650. 'status':xmlrpc.Faults.SUCCESS,
  651. 'description': 'OK'},
  652. ]
  653. def startAllProcesses(self):
  654. from supervisor import xmlrpc
  655. return [
  656. {'name':'foo', 'group':'foo',
  657. 'status': xmlrpc.Faults.SUCCESS,
  658. 'description': 'OK'},
  659. {'name':'foo2', 'group':'foo2',
  660. 'status':xmlrpc.Faults.SUCCESS,
  661. 'description': 'OK'},
  662. {'name':'failed', 'group':'failed_group',
  663. 'status':xmlrpc.Faults.SPAWN_ERROR,
  664. 'description':'SPAWN_ERROR'}
  665. ]
  666. def stopProcessGroup(self, name):
  667. from supervisor import xmlrpc
  668. from xmlrpclib import Fault
  669. if name == 'BAD_NAME':
  670. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  671. return [
  672. {'name':'foo_00', 'group':'foo',
  673. 'status': xmlrpc.Faults.SUCCESS,
  674. 'description': 'OK'},
  675. {'name':'foo_01', 'group':'foo',
  676. 'status':xmlrpc.Faults.SUCCESS,
  677. 'description': 'OK'},
  678. ]
  679. def stopProcess(self, name):
  680. from supervisor import xmlrpc
  681. from xmlrpclib import Fault
  682. if name == 'BAD_NAME:BAD_NAME':
  683. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME:BAD_NAME')
  684. if name == 'BAD_NAME':
  685. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  686. if name == 'NOT_RUNNING':
  687. raise Fault(xmlrpc.Faults.NOT_RUNNING, 'NOT_RUNNING')
  688. if name == 'FAILED':
  689. raise Fault(xmlrpc.Faults.FAILED, 'FAILED')
  690. return True
  691. def stopAllProcesses(self):
  692. from supervisor import xmlrpc
  693. return [
  694. {'name':'foo','group':'foo',
  695. 'status': xmlrpc.Faults.SUCCESS,
  696. 'description': 'OK'},
  697. {'name':'foo2', 'group':'foo2',
  698. 'status':xmlrpc.Faults.SUCCESS,'description': 'OK'},
  699. {'name':'failed', 'group':'failed_group',
  700. 'status':xmlrpc.Faults.BAD_NAME,
  701. 'description':'FAILED'}
  702. ]
  703. def restart(self):
  704. if self._restartable:
  705. self._restarted = True
  706. return
  707. from xmlrpclib import Fault
  708. from supervisor import xmlrpc
  709. raise Fault(xmlrpc.Faults.SHUTDOWN_STATE, '')
  710. def shutdown(self):
  711. if self._restartable:
  712. self._shutdown = True
  713. return
  714. from xmlrpclib import Fault
  715. from supervisor import xmlrpc
  716. raise Fault(xmlrpc.Faults.SHUTDOWN_STATE, '')
  717. def reloadConfig(self):
  718. return [[['added'], ['changed'], ['removed']]]
  719. def addProcessGroup(self, name):
  720. from xmlrpclib import Fault
  721. from supervisor import xmlrpc
  722. if name == 'ALREADY_ADDED':
  723. raise Fault(xmlrpc.Faults.ALREADY_ADDED, '')
  724. if name == 'BAD_NAME':
  725. raise Fault(xmlrpc.Faults.BAD_NAME, '')
  726. if hasattr(self, 'processes'):
  727. self.processes.append(name)
  728. else:
  729. self.processes = [name]
  730. def removeProcessGroup(self, name):
  731. from xmlrpclib import Fault
  732. from supervisor import xmlrpc
  733. if name == 'STILL_RUNNING':
  734. raise Fault(xmlrpc.Faults.STILL_RUNNING, '')
  735. if name == 'BAD_NAME':
  736. raise Fault(xmlrpc.Faults.BAD_NAME, '')
  737. self.processes.remove(name)
  738. def clearProcessStdoutLog(self, name):
  739. from xmlrpclib import Fault
  740. from supervisor import xmlrpc
  741. if name == 'BAD_NAME':
  742. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  743. return True
  744. clearProcessLog = clearProcessStdoutLog
  745. clearProcessStderrLog = clearProcessStdoutLog
  746. clearProcessLogs = clearProcessStdoutLog
  747. def clearAllProcessLogs(self):
  748. from supervisor import xmlrpc
  749. return [
  750. {'name':'foo', 'group':'foo',
  751. 'status':xmlrpc.Faults.SUCCESS,
  752. 'description': 'OK'},
  753. {'name':'foo2', 'group':'foo2',
  754. 'status':xmlrpc.Faults.SUCCESS,
  755. 'description': 'OK'},
  756. {'name':'failed', 'group':'failed_group',
  757. 'status':xmlrpc.Faults.FAILED,
  758. 'description':'FAILED'}
  759. ]
  760. def raiseError(self):
  761. raise ValueError('error')
  762. def getSupervisorVersion(self):
  763. return '3000'
  764. def readLog(self, whence, offset):
  765. if self._readlog_error:
  766. from xmlrpclib import Fault
  767. raise Fault(self._readlog_error, '')
  768. return 'mainlogdata'
  769. class DummyPGroupConfig:
  770. def __init__(self, options, name='whatever', priority=999, pconfigs=None):
  771. self.options = options
  772. self.name = name
  773. self.priority = priority
  774. if pconfigs is None:
  775. pconfigs = []
  776. self.process_configs = pconfigs
  777. self.after_setuid_called = False
  778. self.pool_events = []
  779. self.buffer_size = 10
  780. def after_setuid(self):
  781. self.after_setuid_called = True
  782. def make_group(self):
  783. return DummyProcessGroup(self)
  784. def __repr__(self):
  785. return '<%s instance at %s named %s>' % (self.__class__, id(self),
  786. self.name)
  787. class DummyFCGIGroupConfig(DummyPGroupConfig):
  788. def __init__(self, options, name='whatever', priority=999, pconfigs=None, socket_config=DummySocketConfig(1)):
  789. DummyPGroupConfig.__init__(self, options, name, priority, pconfigs)
  790. self.socket_config = socket_config
  791. class DummyProcessGroup:
  792. def __init__(self, config):
  793. self.config = config
  794. self.transitioned = False
  795. self.all_stopped = False
  796. self.dispatchers = {}
  797. self.unstopped_processes = []
  798. def transition(self):
  799. self.transitioned = True
  800. def stop_all(self):
  801. self.all_stopped = True
  802. def get_unstopped_processes(self):
  803. return self.unstopped_processes
  804. def get_dispatchers(self):
  805. return self.dispatchers
  806. class DummyFCGIProcessGroup(DummyProcessGroup):
  807. def __init__(self, config):
  808. DummyProcessGroup.__init__(self, config)
  809. self.socket_manager = DummySocketManager(config.socket_config)
  810. class PopulatedDummySupervisor(DummySupervisor):
  811. def __init__(self, options, group_name, *pconfigs):
  812. DummySupervisor.__init__(self, options)
  813. self.process_groups = {}
  814. processes = {}
  815. self.group_name = group_name
  816. gconfig = DummyPGroupConfig(options, group_name, pconfigs=pconfigs)
  817. pgroup = DummyProcessGroup(gconfig)
  818. self.process_groups[group_name] = pgroup
  819. for pconfig in pconfigs:
  820. process = DummyProcess(pconfig)
  821. processes[pconfig.name] = process
  822. pgroup.processes = processes
  823. def set_procattr(self, process_name, attr_name, val, group_name=None):
  824. if group_name is None:
  825. group_name = self.group_name
  826. process = self.process_groups[group_name].processes[process_name]
  827. setattr(process, attr_name, val)
  828. class DummyDispatcher:
  829. write_event_handled = False
  830. read_event_handled = False
  831. error_handled = False
  832. logs_reopened = False
  833. logs_removed = False
  834. closed = False
  835. flush_error = None
  836. flushed = False
  837. def __init__(self, readable=False, writable=False, error=False):
  838. self._readable = readable
  839. self._writable = writable
  840. self._error = error
  841. self.input_buffer = ''
  842. if readable:
  843. # only readable dispatchers should have these methods
  844. def reopenlogs():
  845. self.logs_reopened = True
  846. self.reopenlogs = reopenlogs
  847. def removelogs():
  848. self.logs_removed = True
  849. self.removelogs = removelogs
  850. def readable(self):
  851. return self._readable
  852. def writable(self):
  853. return self._writable
  854. def handle_write_event(self):
  855. if self._error:
  856. raise self._error
  857. self.write_event_handled = True
  858. def handle_read_event(self):
  859. if self._error:
  860. raise self._error
  861. self.read_event_handled = True
  862. def handle_error(self):
  863. self.error_handled = True
  864. def close(self):
  865. self.closed = True
  866. def flush(self):
  867. if self.flush_error:
  868. raise OSError(self.flush_error)
  869. self.flushed = True
  870. class DummyStream:
  871. def __init__(self, error=None):
  872. self.error = error
  873. self.closed = False
  874. self.flushed = False
  875. self.written = ''
  876. def close(self):
  877. if self.error:
  878. raise self.error
  879. self.closed = True
  880. def flush(self):
  881. self.flushed = True
  882. def write(self, msg):
  883. if self.error:
  884. raise self.error
  885. self.written +=msg
  886. def seek(self, num, whence=0):
  887. pass
  888. def tell(self):
  889. return len(self.written)
  890. class DummyEvent:
  891. def __init__(self, serial='abc'):
  892. if serial is not None:
  893. self.serial = serial
  894. def __str__(self):
  895. return 'dummy event'
  896. def dummy_handler(event, result):
  897. pass
  898. def rejecting_handler(event, result):
  899. from supervisor.dispatchers import RejectEvent
  900. raise RejectEvent(result)
  901. def exception_handler(event, result):
  902. raise ValueError(result)
  903. def lstrip(s):
  904. strings = [x.strip() for x in s.split('\n')]
  905. return '\n'.join(strings)