Skip to content

Commit

Permalink
Return BAD_NAME if getProcessInfo() can't resolve the name. Fixes #211
Browse files Browse the repository at this point in the history
  • Loading branch information
mnaberez committed Apr 3, 2013
1 parent 4b9d3ee commit c4e0c25
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 47 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Next release
- Fixed a bug where supervisord would crash if the syslog handler was used
and supervisord received SIGUSR2 (log reopen request).

- Fixed an XML-RPC bug where calling supervisor.getProcessInfo() with a bad
name would cause a 500 Internal Server Error rather than the returning
a BAD_NAME fault.

3.0b1 (2012-09-10)
------------------

Expand Down
3 changes: 3 additions & 0 deletions supervisor/rpcinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ def getProcessInfo(self, name):

group, process = self._getGroupAndProcess(name)

if process is None:
raise RPCError(Faults.BAD_NAME, name)

start = int(process.laststart)
stop = int(process.laststop)
now = int(time.time())
Expand Down
108 changes: 61 additions & 47 deletions supervisor/tests/test_rpcinterfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_traverse(self):
'dummy.hello', [1])
self.assertEqual(xmlrpc.traverse(
interface, 'dummy.hello', []), 'Hello!')

class SupervisorNamespaceXMLRPCInterfaceTests(TestBase):
def _getTargetClass(self):
from supervisor import rpcinterface
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_getSupervisorVersion(self):
from supervisor import options
self.assertEqual(version, options.VERSION)
self.assertEqual(interface.update_text, 'getSupervisorVersion')


def test_getIdentification(self):
supervisord = DummySupervisor()
Expand Down Expand Up @@ -439,7 +439,7 @@ def test_startProcess_abnormal_term_process_not_running(self):
time.sleep(.1)
from supervisor import xmlrpc
self._assertRPCError(xmlrpc.Faults.ABNORMAL_TERMINATION, callback)

def test_startProcess_abormal_term_startsecs_exceeded(self):
options = DummyOptions()
pconfig = DummyPConfig(options, 'foo', __file__, autostart=False,
Expand Down Expand Up @@ -876,7 +876,7 @@ def test__interpretProcessInfo(self):
'start':start,
'stop':stop,
'now':_NOW}

description = interface._interpretProcessInfo(running)
self.assertEqual(description, 'pid 1, uptime 0:01:40')

Expand All @@ -887,7 +887,7 @@ def test__interpretProcessInfo(self):
'stop':stop,
'now':_NOW,
'spawnerr':'Hosed'}

description = interface._interpretProcessInfo(fatal)
self.assertEqual(description, 'Hosed')

Expand All @@ -898,10 +898,10 @@ def test__interpretProcessInfo(self):
'stop':stop,
'now':_NOW,
'spawnerr':'',}

description = interface._interpretProcessInfo(fatal2)
self.assertEqual(description, 'unknown error (try "tail fatal")')

stopped = {'name':'stopped',
'pid':3,
'state':ProcessStates.STOPPED,
Expand All @@ -914,7 +914,7 @@ def test__interpretProcessInfo(self):
from datetime import datetime
stoptime = datetime(*time.localtime(stop)[:7])
self.assertEqual(description, stoptime.strftime(_TIMEFORMAT))

stopped2 = {'name':'stopped',
'pid':3,
'state':ProcessStates.STOPPED,
Expand All @@ -925,7 +925,7 @@ def test__interpretProcessInfo(self):

description = interface._interpretProcessInfo(stopped2)
self.assertEqual(description, 'Not started')


def test_getProcessInfo(self):
from supervisor.process import ProcessStates
Expand Down Expand Up @@ -976,6 +976,20 @@ def test_getProcessInfo_logfile_NONE(self):
self.assertEqual(data['logfile'], '')
self.assertEqual(data['stdout_logfile'], '')

def test_getProcessInfo_bad_name(self):
from supervisor import xmlrpc
supervisord = DummySupervisor()
interface = self._makeOne(supervisord)
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
interface.getProcessInfo, 'nonexistant')

def test_getProcessInfo_bad_name_group_only(self):
from supervisor import xmlrpc
supervisord = DummySupervisor()
interface = self._makeOne(supervisord)
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
interface.getProcessInfo, 'grouponly:')

def test_getAllProcessInfo(self):
from supervisor.process import ProcessStates
options = DummyOptions()
Expand Down Expand Up @@ -1036,10 +1050,10 @@ def test_getAllProcessInfo(self):
self.assertEqual(p2info['exitstatus'], 0)
self.assertEqual(p2info['spawnerr'], '')
self.assertEqual(p1info['group'], 'gname')

from datetime import datetime
starttime = datetime(*time.localtime(process2.laststart)[:7])
self.assertEqual(p2info['description'],
self.assertEqual(p2info['description'],
starttime.strftime(_TIMEFORMAT))

def test_readProcessStdoutLog_unreadable(self):
Expand Down Expand Up @@ -1172,7 +1186,7 @@ def test_tailProcessStdoutLog_bad_name(self):
from supervisor import xmlrpc
supervisord = DummySupervisor()
interface = self._makeOne(supervisord)
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
interface.tailProcessStdoutLog, 'BAD_NAME', 0, 10)

def test_tailProcessStdoutLog_all(self):
Expand All @@ -1189,9 +1203,9 @@ def test_tailProcessStdoutLog_all(self):
f = open(logfile, 'w+')
f.write(letters)
f.close()
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=0,

data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=0,
length=len(letters))
self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
self.assertEqual(overflow, False)
Expand All @@ -1216,17 +1230,17 @@ def test_tailProcessStdoutLog_none(self):
f.close()

# offset==logsize
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=len(letters),
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=len(letters),
length=100)
self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
self.assertEqual(overflow, False)
self.assertEqual(offset, len(letters))
self.assertEqual(data, '')

# offset > logsize
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=len(letters)+5,
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=len(letters)+5,
length=100)
self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
self.assertEqual(overflow, False)
Expand All @@ -1250,24 +1264,24 @@ def test_tailProcessStdoutLog_overflow(self):
f.write(letters)
f.close()

data, offset, overflow = interface.tailProcessStdoutLog('foo',
data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=0, length=5)
self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
self.assertEqual(overflow, True)
self.assertEqual(offset, len(letters))
self.assertEqual(data, letters[-5:])
finally:
os.remove(logfile)

def test_tailProcessStdoutLog_unreadable(self):
# test nothing is returned if the log doesn't exist yet
options = DummyOptions()
pconfig = DummyPConfig(options, 'foo', '/bin/foo',
stdout_logfile='/tmp/fooooooo')
supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
interface = self._makeOne(supervisord)
data, offset, overflow = interface.tailProcessStdoutLog('foo',

data, offset, overflow = interface.tailProcessStdoutLog('foo',
offset=0, length=100)
self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
self.assertEqual(overflow, False)
Expand All @@ -1286,7 +1300,7 @@ def test_tailProcessStderrLog_bad_name(self):
from supervisor import xmlrpc
supervisord = DummySupervisor()
interface = self._makeOne(supervisord)
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
self._assertRPCError(xmlrpc.Faults.BAD_NAME,
interface.tailProcessStderrLog, 'BAD_NAME', 0, 10)

def test_tailProcessStderrLog_all(self):
Expand All @@ -1303,9 +1317,9 @@ def test_tailProcessStderrLog_all(self):
f = open(logfile, 'w+')
f.write(letters)
f.close()
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=0,

data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=0,
length=len(letters))
self.assertEqual(interface.update_text, 'tailProcessStderrLog')
self.assertEqual(overflow, False)
Expand All @@ -1330,17 +1344,17 @@ def test_tailProcessStderrLog_none(self):
f.close()

# offset==logsize
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=len(letters),
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=len(letters),
length=100)
self.assertEqual(interface.update_text, 'tailProcessStderrLog')
self.assertEqual(overflow, False)
self.assertEqual(offset, len(letters))
self.assertEqual(data, '')

# offset > logsize
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=len(letters)+5,
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=len(letters)+5,
length=100)
self.assertEqual(interface.update_text, 'tailProcessStderrLog')
self.assertEqual(overflow, False)
Expand All @@ -1364,24 +1378,24 @@ def test_tailProcessStderrLog_overflow(self):
f.write(letters)
f.close()

data, offset, overflow = interface.tailProcessStderrLog('foo',
data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=0, length=5)
self.assertEqual(interface.update_text, 'tailProcessStderrLog')
self.assertEqual(overflow, True)
self.assertEqual(offset, len(letters))
self.assertEqual(data, letters[-5:])
finally:
os.remove(logfile)

def test_tailProcessStderrLog_unreadable(self):
# test nothing is returned if the log doesn't exist yet
options = DummyOptions()
pconfig = DummyPConfig(options, 'foo', '/bin/foo',
stderr_logfile='/tmp/fooooooo')
supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
interface = self._makeOne(supervisord)
data, offset, overflow = interface.tailProcessStderrLog('foo',

data, offset, overflow = interface.tailProcessStderrLog('foo',
offset=0, length=100)
self.assertEqual(interface.update_text, 'tailProcessStderrLog')
self.assertEqual(overflow, False)
Expand Down Expand Up @@ -1418,7 +1432,7 @@ def test_clearProcessLogs_failed(self):
supervisord = DummySupervisor(process_groups={'foo':pgroup})
interface = self._makeOne(supervisord)
self.assertRaises(xmlrpc.RPCError, interface.clearProcessLogs, 'foo')

def test_clearProcessLogAliasedTo_clearProcessLogs(self):
options = DummyOptions()
pconfig = DummyPConfig(options, 'foo', '/bin/foo')
Expand Down Expand Up @@ -1491,7 +1505,7 @@ def test_sendProcessStdin_raises_incorrect_params_when_not_chars(self):
self._assertRPCError(xmlrpc.Faults.INCORRECT_PARAMETERS,
interface.sendProcessStdin,
'process1', thing_not_chars)

def test_sendProcessStdin_raises_bad_name_when_no_process(self):
options = DummyOptions()
supervisord = PopulatedDummySupervisor(options, 'foo')
Expand Down Expand Up @@ -1523,7 +1537,7 @@ def test_sendProcessStdin_raises_not_running_when_killing(self):
self._assertRPCError(xmlrpc.Faults.NOT_RUNNING,
interface.sendProcessStdin,
'process1', 'chars for stdin')

def test_sendProcessStdin_raises_no_file_when_write_raises_epipe(self):
options = DummyOptions()
pconfig1 = DummyPConfig(options, 'process1', 'foo')
Expand Down Expand Up @@ -1568,7 +1582,7 @@ def test_sendRemoteCommEvent_notifies_subscribers(self):
L = []
def callback(event):
L.append(event)

try:
events.callbacks[:] = [(events.RemoteCommunicationEvent, callback)]
result = interface.sendRemoteCommEvent('foo', 'bar')
Expand All @@ -1578,7 +1592,7 @@ def callback(event):

self.assertTrue(result)
self.assertEqual(len(L), 1)
event = L[0]
event = L[0]
self.assertEqual(event.type, 'foo')
self.assertEqual(event.data, 'bar')

Expand All @@ -1591,7 +1605,7 @@ def test_sendRemoteCommEvent_unicode_encoded_to_utf8(self):
L = []
def callback(event):
L.append(event)

try:
events.callbacks[:] = [(events.RemoteCommunicationEvent, callback)]
result = interface.sendRemoteCommEvent(u'fi\xed once', u'fi\xed twice')
Expand All @@ -1601,10 +1615,10 @@ def callback(event):

self.assertTrue(result)
self.assertEqual(len(L), 1)
event = L[0]
event = L[0]
self.assertEqual(event.type, 'fi\xc3\xad once')
self.assertEqual(event.data, 'fi\xc3\xad twice')


class SystemNamespaceXMLRPCInterfaceTests(TestBase):
def _getTargetClass(self):
Expand Down Expand Up @@ -1719,7 +1733,7 @@ def test_allMethodDocs(self):
self.failUnless(type(doctext) == type(''), doctext)

# result tokens

if len(rlines) > 1:
raise AssertionError(
'Duplicate @return values in docs for %s' % k)
Expand Down Expand Up @@ -1753,20 +1767,20 @@ def test_multicall_recursion_guard(self):
from supervisor import xmlrpc
interface = self._makeOne()
callback = interface.multicall([
{'methodName': 'system.multicall', 'params': []},
{'methodName': 'system.multicall', 'params': []},
])

from supervisor import http
result = http.NOT_DONE_YET
while result is http.NOT_DONE_YET:
result = callback()

code = xmlrpc.Faults.INCORRECT_PARAMETERS
desc = xmlrpc.getFaultDescription(code)
recursion_fault = {'faultCode': code, 'faultString': desc}

self.assertEqual(result, [recursion_fault])

def test_multicall_nested_callback(self):
interface = self._makeOne()
callback = interface.multicall([
Expand Down

0 comments on commit c4e0c25

Please sign in to comment.