Thanks, everyone. Attached is the patch with full unit tests.
Chris, I need to update the manual as well for the new fcgi-program options,
socket_owner and socket_mode. I forget where that is. In another svn repo?
Thanks,
Roger
On Fri, Oct 23, 2009 at 9:57 AM, Chris McDonough <[email protected]> wrote:
> Roger Hoover wrote:
>
>> Hmmm...the more I think about it., socket_owner and socket_mode are indeed
>> better names. Chris/Mike, do you want to weigh in on consistency vs.
>> clarity?
>>
>
> I'd be fine with either.
>
> - C
>
>
>
>> On Fri, Oct 23, 2009 at 9:08 AM, Roger Hoover <[email protected]<mailto:
>> [email protected]>> wrote:
>>
>>
>>
>> On Fri, Oct 23, 2009 at 8:57 AM, Grzegorz Nosek <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> On Fri, Oct 23, 2009 at 08:33:28AM -0700, Roger Hoover wrote:
>> > I'm most of the way there on #2. The issue is that as far as
>> I can tell
>> > there's no way to find out the umask for a user so I don't
>> automatically
>> > know what permissions to chmod the FCGI socket with. Now,
>> the choices are
>> >
>> > a) Don't chmod the FCGI socket, just chown it to the uid/gid
>> of the user the
>> > process will run as
>> >
>> > b) Add socket_chown, socket_chmod args that only apply to
>> unix domain
>> > sockets. This allows the most control for the user but the
>> fact that the
>> > params don't always make sense is a bit awkward.
>> >
>> > [fcgi-program:test]
>> > command=/foo/bar.fcgi
>> > socket=unix:///tmp/test.socket
>> > socket_chown=rhoover:wheel ; this option would only apply to
>> unix domain
>> > sockets
>> > socket_chmod=0777 ; this option would only apply to unix
>> domain sockets
>> > user=nobody
>> > process_name=foo_%(process_num)s
>> > numprocs=2
>> >
>> > Anyone have an opinion here?
>>
>> I'm for explicit owner and mode options. Apache-style FastCGI
>> wrappers
>> are a pain.
>>
>>
>> Thanks. I was leaning this direction.
>>
>>
>> Also, my vote would go to naming these options "socket_owner" and
>> "socket_mode" (or "socket_perm(s)"?) as I've heard enough of
>> "setting
>> chmods" in my day ;)
>>
>>
>> That makes sense but I'm going for consistency with the existing
>> unix_http_server section of the config.
>> http://supervisord.org/manual/current/configuration.html#unix_http_server
>>
>>
>> Best regards,
>> Grzegorz Nosek
>>
>>
>>
>>
>
Index: src/supervisor/options.py
===================================================================
--- src/supervisor/options.py (revision 898)
+++ src/supervisor/options.py (working copy)
@@ -645,6 +645,25 @@
continue
program_name = section.split(':', 1)[1]
priority = integer(get(section, 'priority', 999))
+
+ proc_uid = name_to_uid(get(section, 'user', None))
+
+ socket_owner = get(section, 'socket_owner', None)
+ if socket_owner is not None:
+ try:
+ socket_owner = colon_separated_user_group(socket_owner)
+ except ValueError:
+ raise ValueError('Invalid socket_owner value %s'
+ %
socket_owner)
+
+ socket_mode = get(section, 'socket_mode', None)
+ if socket_mode is not None:
+ try:
+ socket_mode = octal_type(socket_mode)
+ except (TypeError, ValueError):
+ raise ValueError('Invalid socket_mode value %s'
+ % socket_mode)
+
socket = get(section, 'socket', None)
if not socket:
raise ValueError('[%s] section requires a "socket" line' %
@@ -654,7 +673,8 @@
'program_name':program_name}
socket = expand(socket, expansions, 'socket')
try:
- socket_config = self.parse_fcgi_socket(socket)
+ socket_config = self.parse_fcgi_socket(socket, proc_uid,
+ socket_owner, socket_mode)
except ValueError, e:
raise ValueError('%s in [%s] socket' % (str(e), section))
@@ -669,7 +689,7 @@
groups.sort()
return groups
- def parse_fcgi_socket(self, sock):
+ def parse_fcgi_socket(self, sock, proc_uid, socket_owner, socket_mode):
if sock.startswith('unix://'):
path = sock[7:]
#Check it's an absolute path
@@ -677,8 +697,22 @@
raise ValueError("Unix socket path %s is not an absolute path",
path)
path = normalize_path(path)
- return UnixStreamSocketConfig(path)
+
+ if socket_owner is None:
+ uid = os.getuid()
+ if proc_uid is not None and proc_uid != uid:
+ socket_owner = (proc_uid, self.get_gid_for_uid(proc_uid))
+
+ if socket_mode is None:
+ socket_mode = 0700
+
+ return UnixStreamSocketConfig(path, owner=socket_owner,
+ mode=socket_mode)
+ if socket_owner is not None or socket_mode is not None:
+ raise ValueError("socket_owner and socket_mode params should"
+ + " only be used with a Unix domain socket")
+
m = re.match(r'tcp://([^\s:]+):(\d+)$', sock)
if m:
host = m.group(1)
@@ -686,6 +720,11 @@
return InetStreamSocketConfig(host, port)
raise ValueError("Bad socket format %s", sock)
+
+ def get_gid_for_uid(self, uid):
+ import pwd
+ pwrec = pwd.getpwuid(uid)
+ return pwrec[3]
def processes_from_section(self, parser, section, group_name,
klass=None):
Index: src/supervisor/datatypes.py
===================================================================
--- src/supervisor/datatypes.py (revision 898)
+++ src/supervisor/datatypes.py (working copy)
@@ -202,7 +202,7 @@
def addr(self): # pragma: no cover
raise NotImplementedError
- def create(self): # pragma: no cover
+ def create_and_bind(self): # pragma: no cover
raise NotImplementedError
class InetStreamSocketConfig(SocketConfig):
@@ -219,28 +219,65 @@
def addr(self):
return (self.host, self.port)
- def create(self):
+ def create_and_bind(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind(self.addr())
return sock
class UnixStreamSocketConfig(SocketConfig):
""" Unix domain socket config helper """
path = None # Unix domain socket path
+ mode = None # Unix permission mode bits for socket
+ owner = None # Tuple (uid, gid) for Unix ownership of socket
+ sock = None # socket object
- def __init__(self, path):
+ def __init__(self, path, **kwargs):
self.path = path
self.url = 'unix://%s' % (path)
+ self.mode = kwargs.get('mode', None)
+ self.owner = kwargs.get('owner', None)
def addr(self):
return self.path
- def create(self):
+ def create_and_bind(self):
if os.path.exists(self.path):
os.unlink(self.path)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.bind(self.addr())
+ try:
+ self._chown()
+ self._chmod()
+ except:
+ sock.close()
+ os.unlink(self.path)
+ raise
return sock
+
+ def get_mode(self):
+ return self.mode
+
+ def get_owner(self):
+ return self.owner
+
+ def _chmod(self):
+ if self.mode is not None:
+ try:
+ os.chmod(self.path, self.mode)
+ except Exception, e:
+ raise ValueError("Could not change permissions of socket "
+ + "file: %s" % (e))
+
+ def _chown(self):
+ if self.owner is not None:
+ try:
+ os.chown(self.path, self.owner[0], self.owner[1])
+ except Exception, e:
+ raise ValueError("Could not change ownership of socket file: "
+ + "%s" % (e))
+
def colon_separated_user_group(arg):
try:
Index: src/supervisor/tests/test_options.py
===================================================================
--- src/supervisor/tests/test_options.py (revision 898)
+++ src/supervisor/tests/test_options.py (working copy)
@@ -8,6 +8,7 @@
import signal
import shutil
import errno
+from mock import Mock, patch, sentinel
from supervisor.tests.base import DummySupervisor
from supervisor.tests.base import DummyLogger
@@ -784,49 +785,93 @@
config.read_string(text)
instance = self._makeOne()
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
-
+
def test_fcgi_programs_from_parser(self):
from supervisor.options import FastCGIGroupConfig
from supervisor.options import FastCGIProcessConfig
text = lstrip("""\
[fcgi-program:foo]
- socket=unix:///tmp/%(program_name)s.sock
+ socket = unix:///tmp/%(program_name)s.sock
+ socket_owner = testuser:testgroup
+ socket_mode = 0666
process_name = %(program_name)s_%(process_num)s
command = /bin/foo
numprocs = 2
priority = 1
[fcgi-program:bar]
- socket=tcp://localhost:6000
+ socket = unix:///tmp/%(program_name)s.sock
process_name = %(program_name)s_%(process_num)s
command = /bin/bar
+ user = testuser
numprocs = 3
+
+ [fcgi-program:flub]
+ socket = unix:///tmp/%(program_name)s.sock
+ command = /bin/flub
+
+ [fcgi-program:cub]
+ socket = tcp://localhost:6000
+ command = /bin/cub
""")
from supervisor.options import UnhosedConfigParser
config = UnhosedConfigParser()
config.read_string(text)
instance = self._makeOne()
- gconfigs = instance.process_groups_from_parser(config)
- self.assertEqual(len(gconfigs), 2)
+
+ #Patch pwd and grp module functions to give us sentinel
+ #uid/gid values so that the test does not depend on
+ #any specific system users
+ pwd_mock = Mock()
+ pwd_mock.return_value = (None, None, sentinel.uid, sentinel.gid)
+ grp_mock = Mock()
+ grp_mock.return_value = (None, None, sentinel.gid)
+ @patch('pwd.getpwuid', pwd_mock)
+ @patch('pwd.getpwnam', pwd_mock)
+ @patch('grp.getgrnam', grp_mock)
+ def get_process_groups(instance, config):
+ return instance.process_groups_from_parser(config)
- gconfig0 = gconfigs[0]
- self.assertEqual(gconfig0.__class__, FastCGIGroupConfig)
- self.assertEqual(gconfig0.name, 'foo')
- self.assertEqual(gconfig0.priority, 1)
- self.assertEqual(gconfig0.socket_config.url,
- 'unix:///tmp/foo.sock')
- self.assertEqual(len(gconfig0.process_configs), 2)
- self.assertEqual(gconfig0.process_configs[0].__class__,
- FastCGIProcessConfig)
- self.assertEqual(gconfig0.process_configs[1].__class__,
- FastCGIProcessConfig)
+ gconfigs = get_process_groups(instance, config)
+ exp_owner = (sentinel.uid, sentinel.gid)
+
+ self.assertEqual(len(gconfigs), 4)
+
+ gconf_foo = gconfigs[0]
+ self.assertEqual(gconf_foo.__class__, FastCGIGroupConfig)
+ self.assertEqual(gconf_foo.name, 'foo')
+ self.assertEqual(gconf_foo.priority, 1)
+ self.assertEqual(gconf_foo.socket_config.url,
+ 'unix:///tmp/foo.sock')
+ self.assertEqual(exp_owner, gconf_foo.socket_config.get_owner())
+ self.assertEqual(0666, gconf_foo.socket_config.get_mode())
+ self.assertEqual(len(gconf_foo.process_configs), 2)
+ pconfig_foo = gconf_foo.process_configs[0]
+ self.assertEqual(pconfig_foo.__class__, FastCGIProcessConfig)
- gconfig1 = gconfigs[1]
- self.assertEqual(gconfig1.name, 'bar')
- self.assertEqual(gconfig1.priority, 999)
- self.assertEqual(gconfig1.socket_config.url,
+ gconf_bar = gconfigs[2]
+ self.assertEqual(gconf_bar.name, 'bar')
+ self.assertEqual(gconf_bar.priority, 999)
+ self.assertEqual(gconf_bar.socket_config.url,
+ 'unix:///tmp/bar.sock')
+ self.assertEqual(exp_owner, gconf_bar.socket_config.get_owner())
+ self.assertEqual(0700, gconf_bar.socket_config.get_mode())
+ self.assertEqual(len(gconf_bar.process_configs), 3)
+
+ gconf_flub = gconfigs[1]
+ self.assertEqual(gconf_flub.name, 'flub')
+ self.assertEqual(gconf_flub.socket_config.url,
+ 'unix:///tmp/flub.sock')
+ self.assertEqual(None, gconf_flub.socket_config.get_owner())
+ self.assertEqual(0700, gconf_flub.socket_config.get_mode())
+ self.assertEqual(len(gconf_flub.process_configs), 1)
+
+ gconf_cub = gconfigs[3]
+ self.assertEqual(gconf_cub.name, 'cub')
+ self.assertEqual(gconf_cub.socket_config.url,
'tcp://localhost:6000')
- self.assertEqual(len(gconfig1.process_configs), 3)
+ self.assertEqual(len(gconf_cub.process_configs), 1)
+
def test_fcgi_program_no_socket(self):
text = lstrip("""\
@@ -901,6 +946,58 @@
config.read_string(text)
instance = self._makeOne()
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
+
+ def test_fcgi_program_socket_owner_set_for_tcp(self):
+ text = lstrip("""\
+ [fcgi-program:foo]
+ socket=tcp://localhost:8000
+ socket_owner=nobody:nobody
+ command = /bin/foo
+ """)
+ from supervisor.options import UnhosedConfigParser
+ config = UnhosedConfigParser()
+ config.read_string(text)
+ instance = self._makeOne()
+
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
+
+ def test_fcgi_program_socket_mode_set_for_tcp(self):
+ text = lstrip("""\
+ [fcgi-program:foo]
+ socket = tcp://localhost:8000
+ socket_mode = 0777
+ command = /bin/foo
+ """)
+ from supervisor.options import UnhosedConfigParser
+ config = UnhosedConfigParser()
+ config.read_string(text)
+ instance = self._makeOne()
+
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
+
+ def test_fcgi_program_bad_socket_owner(self):
+ text = lstrip("""\
+ [fcgi-program:foo]
+ socket = unix:///tmp/foo.sock
+ socket_owner = sometotaljunkuserthatshouldnobethere
+ command = /bin/foo
+ """)
+ from supervisor.options import UnhosedConfigParser
+ config = UnhosedConfigParser()
+ config.read_string(text)
+ instance = self._makeOne()
+
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
+
+ def test_fcgi_program_bad_socket_mode(self):
+ text = lstrip("""\
+ [fcgi-program:foo]
+ socket = unix:///tmp/foo.sock
+ socket_mode = junk
+ command = /bin/foo
+ """)
+ from supervisor.options import UnhosedConfigParser
+ config = UnhosedConfigParser()
+ config.read_string(text)
+ instance = self._makeOne()
+
self.assertRaises(ValueError,instance.process_groups_from_parser,config)
def test_heterogeneous_process_groups_from_parser(self):
text = lstrip("""\
Index: src/supervisor/tests/test_datatypes.py
===================================================================
--- src/supervisor/tests/test_datatypes.py (revision 898)
+++ src/supervisor/tests/test_datatypes.py (working copy)
@@ -5,6 +5,7 @@
import unittest
import socket
import tempfile
+from mock import Mock, patch, sentinel
from supervisor import datatypes
class DatatypesTest(unittest.TestCase):
@@ -176,7 +177,7 @@
def test_url_rejects_urlparse_unrecognized_scheme_with_path(self):
bad_url = "bad://path"
self.assertRaises(ValueError, datatypes.url, bad_url)
-
+
class InetStreamSocketConfigTests(unittest.TestCase):
def _getTargetClass(self):
return datatypes.InetStreamSocketConfig
@@ -187,6 +188,10 @@
def test_url(self):
conf = self._makeOne('127.0.0.1', 8675)
self.assertEqual(conf.url, 'tcp://127.0.0.1:8675')
+
+ def test___str__(self):
+ cfg = self._makeOne('localhost', 65531)
+ self.assertEqual(str(cfg), 'tcp://localhost:65531')
def test_repr(self):
conf = self._makeOne('127.0.0.1', 8675)
@@ -205,32 +210,32 @@
addr = conf.addr()
self.assertEqual(addr, ('localhost', 5001))
- def test_create(self):
+ def test_create_and_bind(self):
conf = self._makeOne('127.0.0.1', 8675)
- sock = conf.create()
+ sock = conf.create_and_bind()
reuse = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
self.assertTrue(reuse)
- sock.close
+ self.assertEquals(conf.addr(), sock.getsockname()) #verifies that bind
was called
+ sock.close()
def test_same_urls_are_equal(self):
- conf1 = self._makeOne('localhost', '5001')
- conf2 = self._makeOne('localhost', '5001')
+ conf1 = self._makeOne('localhost', 5001)
+ conf2 = self._makeOne('localhost', 5001)
self.assertTrue(conf1 == conf2)
self.assertFalse(conf1 != conf2)
def test_diff_urls_are_not_equal(self):
- conf1 = self._makeOne('localhost', '5001')
- conf2 = self._makeOne('localhost', '5002')
+ conf1 = self._makeOne('localhost', 5001)
+ conf2 = self._makeOne('localhost', 5002)
self.assertTrue(conf1 != conf2)
self.assertFalse(conf1 == conf2)
def test_diff_objs_are_not_equal(self):
- conf1 = self._makeOne('localhost', '5001')
+ conf1 = self._makeOne('localhost', 5001)
conf2 = 'blah'
self.assertTrue(conf1 != conf2)
- self.assertFalse(conf1 == conf2)
-
-
+ self.assertFalse(conf1 == conf2)
+
class UnixStreamSocketConfigTests(unittest.TestCase):
def _getTargetClass(self):
return datatypes.UnixStreamSocketConfig
@@ -241,6 +246,10 @@
def test_url(self):
conf = self._makeOne('/tmp/foo.sock')
self.assertEqual(conf.url, 'unix:///tmp/foo.sock')
+
+ def test___str__(self):
+ cfg = self._makeOne('foo/bar')
+ self.assertEqual(str(cfg), 'unix://foo/bar')
def test_repr(self):
conf = self._makeOne('/tmp/foo.sock')
@@ -254,14 +263,43 @@
addr = conf.addr()
self.assertEqual(addr, '/tmp/foo.sock')
- def test_create(self):
+ def test_create_and_bind(self):
(tf_fd, tf_name) = tempfile.mkstemp()
- conf = self._makeOne(tf_name)
- os.close(tf_fd)
- sock = conf.create()
- self.assertFalse(os.path.exists(tf_name))
- sock.close
+ owner = (sentinel.uid, sentinel.gid)
+ mode = sentinel.mode
+ conf = self._makeOne(tf_name, owner=owner, mode=mode)
+ #Patch os.chmod and os.chown functions with mocks
+ #objects so that the test does not depend on
+ #any specific system users or permissions
+ chown_mock = Mock()
+ chmod_mock = Mock()
+ @patch('os.chown', chown_mock)
+ @patch('os.chmod', chmod_mock)
+ def call_create_and_bind(conf):
+ return conf.create_and_bind()
+
+ sock = call_create_and_bind(conf)
+ self.assertTrue(os.path.exists(tf_name))
+ self.assertEquals(conf.addr(), sock.getsockname()) #verifies that bind
was called
+ sock.close()
+ self.assertTrue(os.path.exists(tf_name))
+ os.unlink(tf_name)
+ #Verify that os.chown was called with correct args
+ self.assertEquals(1, chown_mock.call_count)
+ path_arg = chown_mock.call_args[0][0]
+ uid_arg = chown_mock.call_args[0][1]
+ gid_arg = chown_mock.call_args[0][2]
+ self.assertEquals(tf_name, path_arg)
+ self.assertEquals(owner[0], uid_arg)
+ self.assertEquals(owner[1], gid_arg)
+ #Verify that os.chmod was called with correct args
+ self.assertEquals(1, chmod_mock.call_count)
+ path_arg = chmod_mock.call_args[0][0]
+ mode_arg = chmod_mock.call_args[0][1]
+ self.assertEquals(tf_name, path_arg)
+ self.assertEquals(mode, mode_arg)
+
def test_same_paths_are_equal(self):
conf1 = self._makeOne('/tmp/foo.sock')
conf2 = self._makeOne('/tmp/foo.sock')
@@ -278,8 +316,8 @@
conf1 = self._makeOne('/tmp/foo.sock')
conf2 = 'blah'
self.assertTrue(conf1 != conf2)
- self.assertFalse(conf1 == conf2)
-
+ self.assertFalse(conf1 == conf2)
+
class RangeCheckedConversionTests(unittest.TestCase):
def _getTargetClass(self):
from supervisor.datatypes import RangeCheckedConversion
@@ -341,72 +379,6 @@
self.assertEqual(addr.family, socket.AF_INET)
self.assertEqual(addr.address, ('localhost', 8080))
-class TestInetStreamSocketConfig(unittest.TestCase):
- def _getTargetClass(self):
- from supervisor.datatypes import InetStreamSocketConfig
- return InetStreamSocketConfig
-
- def _makeOne(self, host, port):
- return self._getTargetClass()(host, port)
-
- def test_addr(self):
- cfg = self._makeOne('localhost', 8080)
- self.assertEqual(cfg.addr(), ('localhost', 8080))
-
- def test_create(self):
- cfg = self._makeOne('localhost', 65531)
- sock = cfg.create()
- sock.close()
-
- def test___str__(self):
- cfg = self._makeOne('localhost', 65531)
- self.assertEqual(str(cfg), 'tcp://localhost:65531')
-
- def test__eq__(self):
- cfg = self._makeOne('localhost', 65531)
- cfg2 = self._makeOne('localhost', 65531)
- self.failUnless(cfg == cfg2)
-
- def test__ne__(self):
- cfg = self._makeOne('localhost', 65531)
- cfg2 = self._makeOne('localhost', 65532)
- self.failUnless(cfg != cfg2)
-
-class TestUnixStreamSocketConfig(unittest.TestCase):
- def _getTargetClass(self):
- from supervisor.datatypes import UnixStreamSocketConfig
- return UnixStreamSocketConfig
-
- def _makeOne(self, path):
- return self._getTargetClass()(path)
-
- def test_addr(self):
- cfg = self._makeOne('/foo/bar')
- self.assertEqual(cfg.addr(), '/foo/bar')
-
- def test_create(self):
- import tempfile
- fn = tempfile.mktemp()
- cfg = self._makeOne(fn)
- sock = cfg.create()
- sock.close()
- if os.path.exists(fn):
- os.unlink(fn)
-
- def test___str__(self):
- cfg = self._makeOne('foo/bar')
- self.assertEqual(str(cfg), 'unix://foo/bar')
-
- def test__eq__(self):
- cfg = self._makeOne('/foo/bar')
- cfg2 = self._makeOne('/foo/bar')
- self.failUnless(cfg == cfg2)
-
- def test__ne__(self):
- cfg = self._makeOne('/foo/bar')
- cfg2 = self._makeOne('/foo/bar2')
- self.failUnless(cfg != cfg2)
-
class TestColonSeparatedUserGroup(unittest.TestCase):
def _callFUT(self, arg):
from supervisor.datatypes import colon_separated_user_group
Index: src/supervisor/tests/base.py
===================================================================
--- src/supervisor/tests/base.py (revision 898)
+++ src/supervisor/tests/base.py (working copy)
@@ -333,7 +333,7 @@
def __ne__(self, other):
return not self.__eq__(other)
- def create(self):
+ def create_and_bind(self):
return DummySocket(self.fd)
class DummySocketManager:
Index: src/supervisor/tests/test_socket_manager.py
===================================================================
--- src/supervisor/tests/test_socket_manager.py (revision 898)
+++ src/supervisor/tests/test_socket_manager.py (working copy)
@@ -174,8 +174,7 @@
sock_manager = self._makeOne(conf)
sock = sock_manager.get_socket()
self.assertTrue(sock_manager.is_prepared())
- self.assertTrue(sock.bind_called)
- self.assertEqual(sock.bind_addr, 'dummy addr')
+ self.assertFalse(sock.bind_called)
self.assertTrue(sock.listen_called)
self.assertEqual(sock.listen_backlog, socket.SOMAXCONN)
self.assertFalse(sock.close_called)
Index: src/supervisor/process.py
===================================================================
--- src/supervisor/process.py (revision 898)
+++ src/supervisor/process.py (working copy)
@@ -681,8 +681,9 @@
sockManagerKlass = kwargs.get('socketManager', SocketManager)
self.socket_manager = sockManagerKlass(config.socket_config,
logger=config.options.logger)
- #It's not required to call get_socket() here but we want
- #to fail early during start up if there is a config error
+
+ # It's not required to call get_socket() here but we want
+ # to fail early during start up if there is a config error
try:
sock = self.socket_manager.get_socket()
except Exception, e:
Index: src/supervisor/socket_manager.py
===================================================================
--- src/supervisor/socket_manager.py (revision 898)
+++ src/supervisor/socket_manager.py (working copy)
@@ -107,8 +107,7 @@
if not self.prepared:
if self.logger:
self.logger.info('Creating socket %s' % self.socket_config)
- self.socket = self.socket_config.create()
- self.socket.bind(self.socket_config.addr())
+ self.socket = self.socket_config.create_and_bind()
self.socket.listen(socket.SOMAXCONN)
self.prepared = True
Index: setup.py
===================================================================
--- setup.py (revision 898)
+++ setup.py (working copy)
@@ -87,7 +87,7 @@
)],
install_requires = requires,
extras_require = {'iterparse':['cElementTree >= 1.0.2']},
- tests_require = requires,
+ tests_require = requires + ['mock >= 0.5.0'],
include_package_data = True,
zip_safe = False,
namespace_packages = ['supervisor'],
_______________________________________________
Supervisor-users mailing list
[email protected]
http://lists.supervisord.org/mailman/listinfo/supervisor-users