base.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  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. def __init__(self):
  208. self.reopened = False
  209. self.removed = False
  210. self.closed = False
  211. self.data = []
  212. def info(self, msg, **kw):
  213. if kw:
  214. msg = msg % kw
  215. self.data.append(msg)
  216. warn = debug = critical = trace = error = blather = info
  217. def log(self, level, msg, **kw):
  218. if kw:
  219. msg = msg % kw
  220. self.data.append(msg)
  221. def reopen(self):
  222. self.reopened = True
  223. def close(self):
  224. self.closed = True
  225. def remove(self):
  226. self.removed = True
  227. def flush(self):
  228. self.flushed = True
  229. def getvalue(self):
  230. return ''.join(self.data)
  231. class DummySupervisor:
  232. def __init__(self, options=None, state=None, process_groups=None):
  233. if options is None:
  234. self.options = DummyOptions()
  235. else:
  236. self.options = options
  237. if state is None:
  238. from supervisor.supervisord import SupervisorStates
  239. self.options.mood = SupervisorStates.RUNNING
  240. else:
  241. self.options.mood = state
  242. if process_groups is None:
  243. self.process_groups = {}
  244. else:
  245. self.process_groups = process_groups
  246. def get_state(self):
  247. return self.options.mood
  248. class DummySocket:
  249. bind_called = False
  250. bind_addr = None
  251. listen_called = False
  252. listen_backlog = None
  253. close_called = False
  254. def __init__(self, fd):
  255. self.fd = fd
  256. def fileno(self):
  257. return self.fd
  258. def bind(self, addr):
  259. self.bind_called = True
  260. self.bind_addr = addr
  261. def listen(self, backlog):
  262. self.listen_called = True
  263. self.listen_backlog = backlog
  264. def close(self):
  265. self.close_called = True
  266. def __str__(self):
  267. return 'dummy socket'
  268. class DummySocketConfig:
  269. def __init__(self, fd):
  270. self.fd = fd
  271. def addr(self):
  272. return 'dummy addr'
  273. def __eq__(self, other):
  274. return self.fd == other.fd
  275. def __ne__(self, other):
  276. return not self.__eq__(other)
  277. def create_and_bind(self):
  278. return DummySocket(self.fd)
  279. class DummySocketManager:
  280. def __init__(self, config, **kwargs):
  281. self._config = config
  282. def config(self):
  283. return self._config
  284. def get_socket(self):
  285. return DummySocket(self._config.fd)
  286. class DummyProcess:
  287. # Initial state; overridden by instance variables
  288. pid = 0 # Subprocess pid; 0 when not running
  289. laststart = 0 # Last time the subprocess was started; 0 if never
  290. laststop = 0 # Last time the subprocess was stopped; 0 if never
  291. delay = 0 # If nonzero, delay starting or killing until this time
  292. administrative_stop = 0 # true if the process has been stopped by an admin
  293. system_stop = 0 # true if the process has been stopped by the system
  294. killing = 0 # flag determining whether we are trying to kill this proc
  295. backoff = 0 # backoff counter (to backofflimit)
  296. waitstatus = None
  297. exitstatus = None
  298. pipes = None
  299. rpipes = None
  300. dispatchers = None
  301. stdout_logged = ''
  302. stderr_logged = ''
  303. spawnerr = None
  304. stdout_buffer = '' # buffer of characters from child stdout output to log
  305. stderr_buffer = '' # buffer of characters from child stderr output to log
  306. stdin_buffer = '' # buffer of characters to send to child process' stdin
  307. listener_state = None
  308. group = None
  309. def __init__(self, config, state=None):
  310. self.config = config
  311. self.logsremoved = False
  312. self.stop_called = False
  313. self.backoff_secs = None
  314. self.spawned = False
  315. if state is None:
  316. from supervisor.process import ProcessStates
  317. state = ProcessStates.RUNNING
  318. self.state = state
  319. self.error_at_clear = False
  320. self.killed_with = None
  321. self.drained = False
  322. self.stdout_buffer = ''
  323. self.stderr_buffer = ''
  324. self.stdout_logged = ''
  325. self.stderr_logged = ''
  326. self.stdin_buffer = ''
  327. self.pipes = {}
  328. self.rpipes = {}
  329. self.dispatchers = {}
  330. self.finished = None
  331. self.logs_reopened = False
  332. self.execv_arg_exception = None
  333. self.input_fd_drained = None
  334. self.output_fd_drained = None
  335. self.transitioned = False
  336. self.write_error = None
  337. def reopenlogs(self):
  338. self.logs_reopened = True
  339. def removelogs(self):
  340. if self.error_at_clear:
  341. raise IOError('whatever')
  342. self.logsremoved = True
  343. def get_state(self):
  344. return self.state
  345. def stop(self):
  346. self.stop_called = True
  347. self.killing = False
  348. from supervisor.process import ProcessStates
  349. self.state = ProcessStates.STOPPED
  350. def kill(self, signal):
  351. self.killed_with = signal
  352. def spawn(self):
  353. self.spawned = True
  354. from supervisor.process import ProcessStates
  355. self.state = ProcessStates.RUNNING
  356. def drain(self):
  357. self.drained = True
  358. def __cmp__(self, other):
  359. return cmp(self.config.priority, other.config.priority)
  360. def readable_fds(self):
  361. return []
  362. def record_output(self):
  363. self.stdout_logged += self.stdout_buffer
  364. self.stdout_buffer = ''
  365. self.stderr_logged += self.stderr_buffer
  366. self.stderr_buffer = ''
  367. def finish(self, pid, sts):
  368. self.finished = pid, sts
  369. def give_up(self):
  370. from supervisor.process import ProcessStates
  371. self.state = ProcessStates.FATAL
  372. def get_execv_args(self):
  373. if self.execv_arg_exception:
  374. raise self.execv_arg_exception('whatever')
  375. import shlex
  376. commandargs = shlex.split(self.config.command)
  377. program = commandargs[0]
  378. return program, commandargs
  379. def drain_output_fd(self, fd):
  380. self.output_fd_drained = fd
  381. def drain_input_fd(self, fd):
  382. self.input_fd_drained = fd
  383. def write(self, chars):
  384. if self.write_error:
  385. raise OSError(self.write_error)
  386. self.stdin_buffer += chars
  387. def transition(self):
  388. self.transitioned = True
  389. class DummyPConfig:
  390. def __init__(self, options, name, command, directory=None, umask=None,
  391. priority=999, autostart=True,
  392. autorestart=True, startsecs=10, startretries=999,
  393. uid=None, stdout_logfile=None, stdout_capture_maxbytes=0,
  394. stdout_events_enabled=False,
  395. stdout_logfile_backups=0, stdout_logfile_maxbytes=0,
  396. stderr_logfile=None, stderr_capture_maxbytes=0,
  397. stderr_events_enabled=False,
  398. stderr_logfile_backups=0, stderr_logfile_maxbytes=0,
  399. redirect_stderr=False,
  400. stopsignal=None, stopwaitsecs=10, stopasgroup=False, killasgroup=False,
  401. exitcodes=(0,2), environment=None, serverurl=None):
  402. self.options = options
  403. self.name = name
  404. self.command = command
  405. self.priority = priority
  406. self.autostart = autostart
  407. self.autorestart = autorestart
  408. self.startsecs = startsecs
  409. self.startretries = startretries
  410. self.uid = uid
  411. self.stdout_logfile = stdout_logfile
  412. self.stdout_capture_maxbytes = stdout_capture_maxbytes
  413. self.stdout_events_enabled = stdout_events_enabled
  414. self.stdout_logfile_backups = stdout_logfile_backups
  415. self.stdout_logfile_maxbytes = stdout_logfile_maxbytes
  416. self.stderr_logfile = stderr_logfile
  417. self.stderr_capture_maxbytes = stderr_capture_maxbytes
  418. self.stderr_events_enabled = stderr_events_enabled
  419. self.stderr_logfile_backups = stderr_logfile_backups
  420. self.stderr_logfile_maxbytes = stderr_logfile_maxbytes
  421. self.redirect_stderr = redirect_stderr
  422. if stopsignal is None:
  423. import signal
  424. stopsignal = signal.SIGTERM
  425. self.stopsignal = stopsignal
  426. self.stopwaitsecs = stopwaitsecs
  427. self.stopasgroup = stopasgroup
  428. self.killasgroup = killasgroup
  429. self.exitcodes = exitcodes
  430. self.environment = environment
  431. self.directory = directory
  432. self.umask = umask
  433. self.autochildlogs_created = False
  434. self.serverurl = serverurl
  435. def create_autochildlogs(self):
  436. self.autochildlogs_created = True
  437. def make_process(self, group=None):
  438. process = DummyProcess(self)
  439. process.group = group
  440. return process
  441. def make_dispatchers(self, proc):
  442. use_stderr = not self.redirect_stderr
  443. pipes = self.options.make_pipes(use_stderr)
  444. stdout_fd,stderr_fd,stdin_fd = (pipes['stdout'],pipes['stderr'],
  445. pipes['stdin'])
  446. dispatchers = {}
  447. if stdout_fd is not None:
  448. dispatchers[stdout_fd] = DummyDispatcher(readable=True)
  449. if stderr_fd is not None:
  450. dispatchers[stderr_fd] = DummyDispatcher(readable=True)
  451. if stdin_fd is not None:
  452. dispatchers[stdin_fd] = DummyDispatcher(writable=True)
  453. return dispatchers, pipes
  454. def makeExecutable(file, substitutions=None):
  455. import os
  456. import sys
  457. import tempfile
  458. if substitutions is None:
  459. substitutions = {}
  460. data = open(file).read()
  461. last = os.path.split(file)[1]
  462. substitutions['PYTHON'] = sys.executable
  463. for key in substitutions.keys():
  464. data = data.replace('<<%s>>' % key.upper(), substitutions[key])
  465. tmpnam = tempfile.mktemp(prefix=last)
  466. f = open(tmpnam, 'w')
  467. f.write(data)
  468. f.close()
  469. os.chmod(tmpnam, 0755)
  470. return tmpnam
  471. def makeSpew(unkillable=False):
  472. import os
  473. here = os.path.dirname(__file__)
  474. if not unkillable:
  475. return makeExecutable(os.path.join(here, 'fixtures/spew.py'))
  476. return makeExecutable(os.path.join(here, 'fixtures/unkillable_spew.py'))
  477. class DummyMedusaServerLogger:
  478. def __init__(self):
  479. self.logged = []
  480. def log(self, category, msg):
  481. self.logged.append((category, msg))
  482. class DummyMedusaServer:
  483. def __init__(self):
  484. self.logger = DummyMedusaServerLogger()
  485. class DummyMedusaChannel:
  486. def __init__(self):
  487. self.server = DummyMedusaServer()
  488. self.producer = None
  489. def push_with_producer(self, producer):
  490. self.producer = producer
  491. def close_when_done(self):
  492. pass
  493. class DummyRequest:
  494. command = 'GET'
  495. _error = None
  496. _done = False
  497. version = '1.0'
  498. def __init__(self, path, params, query, fragment, env=None):
  499. self.args = path, params, query, fragment
  500. self.producers = []
  501. self.headers = {}
  502. self.header = []
  503. self.outgoing = []
  504. self.channel = DummyMedusaChannel()
  505. if env is None:
  506. self.env = {}
  507. else:
  508. self.env = env
  509. def split_uri(self):
  510. return self.args
  511. def error(self, code):
  512. self._error = code
  513. def push(self, producer):
  514. self.producers.append(producer)
  515. def __setitem__(self, header, value):
  516. self.headers[header] = value
  517. def has_key(self, header):
  518. return self.headers.has_key(header)
  519. def done(self):
  520. self._done = True
  521. def build_reply_header(self):
  522. return ''
  523. def log(self, *arg, **kw):
  524. pass
  525. def cgi_environment(self):
  526. return self.env
  527. def get_server_url(self):
  528. return 'http://example.com'
  529. class DummyRPCInterfaceFactory:
  530. def __init__(self, supervisord, **config):
  531. self.supervisord = supervisord
  532. self.config = config
  533. class DummyRPCServer:
  534. def __init__(self):
  535. self.supervisor = DummySupervisorRPCNamespace()
  536. self.system = DummySystemRPCNamespace()
  537. class DummySystemRPCNamespace:
  538. pass
  539. class DummySupervisorRPCNamespace:
  540. _restartable = True
  541. _restarted = False
  542. _shutdown = False
  543. _readlog_error = False
  544. from supervisor.process import ProcessStates
  545. all_process_info = [
  546. {
  547. 'name':'foo',
  548. 'group':'foo',
  549. 'pid':11,
  550. 'state':ProcessStates.RUNNING,
  551. 'statename':'RUNNING',
  552. 'start':_NOW - 100,
  553. 'stop':0,
  554. 'spawnerr':'',
  555. 'now':_NOW,
  556. 'description':'foo description',
  557. },
  558. {
  559. 'name':'bar',
  560. 'group':'bar',
  561. 'pid':12,
  562. 'state':ProcessStates.FATAL,
  563. 'statename':'FATAL',
  564. 'start':_NOW - 100,
  565. 'stop':_NOW - 50,
  566. 'spawnerr':'screwed',
  567. 'now':_NOW,
  568. 'description':'bar description',
  569. },
  570. {
  571. 'name':'baz_01',
  572. 'group':'baz',
  573. 'pid':13,
  574. 'state':ProcessStates.STOPPED,
  575. 'statename':'STOPPED',
  576. 'start':_NOW - 100,
  577. 'stop':_NOW - 25,
  578. 'spawnerr':'',
  579. 'now':_NOW,
  580. 'description':'baz description',
  581. },
  582. ]
  583. def getAPIVersion(self):
  584. return '3.0'
  585. getVersion = getAPIVersion # deprecated
  586. def getPID(self):
  587. return 42
  588. def readProcessStdoutLog(self, name, offset, length):
  589. from supervisor import xmlrpc
  590. import xmlrpclib
  591. if name == 'BAD_NAME':
  592. raise xmlrpclib.Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  593. elif name == 'FAILED':
  594. raise xmlrpclib.Fault(xmlrpc.Faults.FAILED, 'FAILED')
  595. elif name == 'NO_FILE':
  596. raise xmlrpclib.Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  597. a = 'output line\n' * 10
  598. return a[offset:]
  599. readProcessLog = readProcessStdoutLog
  600. readProcessStderrLog = readProcessStdoutLog
  601. def getAllProcessInfo(self):
  602. return self.all_process_info
  603. def getProcessInfo(self, name):
  604. from supervisor import xmlrpc
  605. import xmlrpclib
  606. from supervisor.process import ProcessStates
  607. for i in self.all_process_info:
  608. if i['name']==name:
  609. info=i
  610. return info
  611. if name == 'BAD_NAME':
  612. raise xmlrpclib.Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  613. if name == 'FAILED':
  614. raise xmlrpclib.Fault(xmlrpc.Faults.FAILED, 'FAILED')
  615. if name == 'NO_FILE':
  616. raise xmlrpclib.Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  617. def startProcess(self, name):
  618. from supervisor import xmlrpc
  619. from xmlrpclib import Fault
  620. if name == 'BAD_NAME:BAD_NAME':
  621. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME:BAD_NAME')
  622. if name == 'BAD_NAME':
  623. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  624. if name == 'NO_FILE':
  625. raise Fault(xmlrpc.Faults.NO_FILE, 'NO_FILE')
  626. if name == 'NOT_EXECUTABLE':
  627. raise Fault(xmlrpc.Faults.NOT_EXECUTABLE, 'NOT_EXECUTABLE')
  628. if name == 'ALREADY_STARTED':
  629. raise Fault(xmlrpc.Faults.ALREADY_STARTED, 'ALREADY_STARTED')
  630. if name == 'SPAWN_ERROR':
  631. raise Fault(xmlrpc.Faults.SPAWN_ERROR, 'SPAWN_ERROR')
  632. return True
  633. def startProcessGroup(self, name):
  634. from supervisor import xmlrpc
  635. return [
  636. {'name':'foo_00', 'group':'foo',
  637. 'status': xmlrpc.Faults.SUCCESS,
  638. 'description': 'OK'},
  639. {'name':'foo_01', 'group':'foo',
  640. 'status':xmlrpc.Faults.SUCCESS,
  641. 'description': 'OK'},
  642. ]
  643. def startAllProcesses(self):
  644. from supervisor import xmlrpc
  645. return [
  646. {'name':'foo', 'group':'foo',
  647. 'status': xmlrpc.Faults.SUCCESS,
  648. 'description': 'OK'},
  649. {'name':'foo2', 'group':'foo2',
  650. 'status':xmlrpc.Faults.SUCCESS,
  651. 'description': 'OK'},
  652. {'name':'failed', 'group':'failed_group',
  653. 'status':xmlrpc.Faults.SPAWN_ERROR,
  654. 'description':'SPAWN_ERROR'}
  655. ]
  656. def stopProcessGroup(self, name):
  657. from supervisor import xmlrpc
  658. return [
  659. {'name':'foo_00', 'group':'foo',
  660. 'status': xmlrpc.Faults.SUCCESS,
  661. 'description': 'OK'},
  662. {'name':'foo_01', 'group':'foo',
  663. 'status':xmlrpc.Faults.SUCCESS,
  664. 'description': 'OK'},
  665. ]
  666. def stopProcess(self, name):
  667. from supervisor import xmlrpc
  668. from xmlrpclib import Fault
  669. if name == 'BAD_NAME:BAD_NAME':
  670. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME:BAD_NAME')
  671. if name == 'BAD_NAME':
  672. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  673. if name == 'NOT_RUNNING':
  674. raise Fault(xmlrpc.Faults.NOT_RUNNING, 'NOT_RUNNING')
  675. if name == 'FAILED':
  676. raise Fault(xmlrpc.Faults.FAILED, 'FAILED')
  677. return True
  678. def stopAllProcesses(self):
  679. from supervisor import xmlrpc
  680. return [
  681. {'name':'foo','group':'foo',
  682. 'status': xmlrpc.Faults.SUCCESS,
  683. 'description': 'OK'},
  684. {'name':'foo2', 'group':'foo2',
  685. 'status':xmlrpc.Faults.SUCCESS,'description': 'OK'},
  686. {'name':'failed', 'group':'failed_group',
  687. 'status':xmlrpc.Faults.BAD_NAME,
  688. 'description':'FAILED'}
  689. ]
  690. def restart(self):
  691. if self._restartable:
  692. self._restarted = True
  693. return
  694. from xmlrpclib import Fault
  695. from supervisor import xmlrpc
  696. raise Fault(xmlrpc.Faults.SHUTDOWN_STATE, '')
  697. def shutdown(self):
  698. if self._restartable:
  699. self._shutdown = True
  700. return
  701. from xmlrpclib import Fault
  702. from supervisor import xmlrpc
  703. raise Fault(xmlrpc.Faults.SHUTDOWN_STATE, '')
  704. def reloadConfig(self):
  705. return [[['added'], ['changed'], ['removed']]]
  706. def addProcessGroup(self, name):
  707. from xmlrpclib import Fault
  708. from supervisor import xmlrpc
  709. if name == 'ALREADY_ADDED':
  710. raise Fault(xmlrpc.Faults.ALREADY_ADDED, '')
  711. if name == 'BAD_NAME':
  712. raise Fault(xmlrpc.Faults.BAD_NAME, '')
  713. if hasattr(self, 'processes'):
  714. self.processes.append(name)
  715. else:
  716. self.processes = [name]
  717. def removeProcessGroup(self, name):
  718. from xmlrpclib import Fault
  719. from supervisor import xmlrpc
  720. if name == 'STILL_RUNNING':
  721. raise Fault(xmlrpc.Faults.STILL_RUNNING, '')
  722. if name == 'BAD_NAME':
  723. raise Fault(xmlrpc.Faults.BAD_NAME, '')
  724. self.processes.remove(name)
  725. def clearProcessStdoutLog(self, name):
  726. from xmlrpclib import Fault
  727. from supervisor import xmlrpc
  728. if name == 'BAD_NAME':
  729. raise Fault(xmlrpc.Faults.BAD_NAME, 'BAD_NAME')
  730. return True
  731. clearProcessLog = clearProcessStdoutLog
  732. clearProcessStderrLog = clearProcessStdoutLog
  733. clearProcessLogs = clearProcessStdoutLog
  734. def clearAllProcessLogs(self):
  735. from supervisor import xmlrpc
  736. return [
  737. {'name':'foo', 'group':'foo',
  738. 'status':xmlrpc.Faults.SUCCESS,
  739. 'description': 'OK'},
  740. {'name':'foo2', 'group':'foo2',
  741. 'status':xmlrpc.Faults.SUCCESS,
  742. 'description': 'OK'},
  743. {'name':'failed', 'group':'failed_group',
  744. 'status':xmlrpc.Faults.FAILED,
  745. 'description':'FAILED'}
  746. ]
  747. def raiseError(self):
  748. raise ValueError('error')
  749. def getSupervisorVersion(self):
  750. return '3000'
  751. def readLog(self, whence, offset):
  752. if self._readlog_error:
  753. from xmlrpclib import Fault
  754. raise Fault(self._readlog_error, '')
  755. return 'mainlogdata'
  756. class DummyPGroupConfig:
  757. def __init__(self, options, name='whatever', priority=999, pconfigs=None):
  758. self.options = options
  759. self.name = name
  760. self.priority = priority
  761. if pconfigs is None:
  762. pconfigs = []
  763. self.process_configs = pconfigs
  764. self.after_setuid_called = False
  765. self.pool_events = []
  766. self.buffer_size = 10
  767. def after_setuid(self):
  768. self.after_setuid_called = True
  769. def make_group(self):
  770. return DummyProcessGroup(self)
  771. def __repr__(self):
  772. return '<%s instance at %s named %s>' % (self.__class__, id(self),
  773. self.name)
  774. class DummyFCGIGroupConfig(DummyPGroupConfig):
  775. def __init__(self, options, name='whatever', priority=999, pconfigs=None, socket_config=DummySocketConfig(1)):
  776. DummyPGroupConfig.__init__(self, options, name, priority, pconfigs)
  777. self.socket_config = socket_config
  778. class DummyProcessGroup:
  779. def __init__(self, config):
  780. self.config = config
  781. self.transitioned = False
  782. self.all_stopped = False
  783. self.dispatchers = {}
  784. self.unstopped_processes = []
  785. def transition(self):
  786. self.transitioned = True
  787. def stop_all(self):
  788. self.all_stopped = True
  789. def get_unstopped_processes(self):
  790. return self.unstopped_processes
  791. def get_dispatchers(self):
  792. return self.dispatchers
  793. class DummyFCGIProcessGroup(DummyProcessGroup):
  794. def __init__(self, config):
  795. DummyProcessGroup.__init__(self, config)
  796. self.socket_manager = DummySocketManager(config.socket_config)
  797. class PopulatedDummySupervisor(DummySupervisor):
  798. def __init__(self, options, group_name, *pconfigs):
  799. DummySupervisor.__init__(self, options)
  800. self.process_groups = {}
  801. processes = {}
  802. self.group_name = group_name
  803. gconfig = DummyPGroupConfig(options, group_name, pconfigs=pconfigs)
  804. pgroup = DummyProcessGroup(gconfig)
  805. self.process_groups[group_name] = pgroup
  806. for pconfig in pconfigs:
  807. process = DummyProcess(pconfig)
  808. processes[pconfig.name] = process
  809. pgroup.processes = processes
  810. def set_procattr(self, process_name, attr_name, val, group_name=None):
  811. if group_name is None:
  812. group_name = self.group_name
  813. process = self.process_groups[group_name].processes[process_name]
  814. setattr(process, attr_name, val)
  815. class DummyDispatcher:
  816. write_event_handled = False
  817. read_event_handled = False
  818. error_handled = False
  819. logs_reopened = False
  820. logs_removed = False
  821. closed = False
  822. flush_error = None
  823. flushed = False
  824. def __init__(self, readable=False, writable=False, error=False):
  825. self._readable = readable
  826. self._writable = writable
  827. self._error = error
  828. self.input_buffer = ''
  829. if readable:
  830. # only readable dispatchers should have these methods
  831. def reopenlogs():
  832. self.logs_reopened = True
  833. self.reopenlogs = reopenlogs
  834. def removelogs():
  835. self.logs_removed = True
  836. self.removelogs = removelogs
  837. def readable(self):
  838. return self._readable
  839. def writable(self):
  840. return self._writable
  841. def handle_write_event(self):
  842. if self._error:
  843. raise self._error
  844. self.write_event_handled = True
  845. def handle_read_event(self):
  846. if self._error:
  847. raise self._error
  848. self.read_event_handled = True
  849. def handle_error(self):
  850. self.error_handled = True
  851. def close(self):
  852. self.closed = True
  853. def flush(self):
  854. if self.flush_error:
  855. raise OSError(self.flush_error)
  856. self.flushed = True
  857. class DummyStream:
  858. def __init__(self, error=None):
  859. self.error = error
  860. self.closed = False
  861. self.flushed = False
  862. self.written = ''
  863. def close(self):
  864. if self.error:
  865. raise self.error
  866. self.closed = True
  867. def flush(self):
  868. self.flushed = True
  869. def write(self, msg):
  870. if self.error:
  871. raise self.error
  872. self.written +=msg
  873. def seek(self, num, whence=0):
  874. pass
  875. def tell(self):
  876. return len(self.written)
  877. class DummyEvent:
  878. def __init__(self, serial='abc'):
  879. if serial is not None:
  880. self.serial = serial
  881. def __str__(self):
  882. return 'dummy event'
  883. def dummy_handler(event, result):
  884. pass
  885. def rejecting_handler(event, result):
  886. from supervisor.dispatchers import RejectEvent
  887. raise RejectEvent(result)
  888. def exception_handler(event, result):
  889. raise ValueError(result)
  890. def lstrip(s):
  891. strings = [x.strip() for x in s.split('\n')]
  892. return '\n'.join(strings)