Permalink
Browse files

Return BAD_NAME if getProcessInfo() can't resolve the name. Fixes #211

  • Loading branch information...
1 parent 4b9d3ee commit c4e0c25925ca2c3dbf1b8d655bf438ef8a19c61a @mnaberez mnaberez committed Apr 3, 2013
Showing with 68 additions and 47 deletions.
  1. +4 −0 CHANGES.txt
  2. +3 −0 supervisor/rpcinterface.py
  3. +61 −47 supervisor/tests/test_rpcinterfaces.py
View
@@ -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)
------------------
@@ -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())
@@ -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
@@ -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()
@@ -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,
@@ -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')
@@ -887,7 +887,7 @@ def test__interpretProcessInfo(self):
'stop':stop,
'now':_NOW,
'spawnerr':'Hosed'}
-
+
description = interface._interpretProcessInfo(fatal)
self.assertEqual(description, 'Hosed')
@@ -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,
@@ -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,
@@ -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
@@ -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()
@@ -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):
@@ -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):
@@ -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)
@@ -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)
@@ -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)
@@ -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):
@@ -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)
@@ -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)
@@ -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)
@@ -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')
@@ -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')
@@ -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')
@@ -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')
@@ -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')
@@ -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')
@@ -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):
@@ -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)
@@ -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([

0 comments on commit c4e0c25

Please sign in to comment.