Skip to content
This repository has been archived by the owner on Sep 8, 2020. It is now read-only.

Commit

Permalink
re-create Unix domain sockets when binding,
Browse files Browse the repository at this point in the history
to avoid losing the monitor on alternating restarts
  • Loading branch information
freddrake committed Apr 27, 2012
1 parent f9896f4 commit f46eeeb
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 5 deletions.
13 changes: 13 additions & 0 deletions src/zc/monitor/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@
Change History
==============

0.3.1 (2012-04-27)
------------------

- When binding the monitor to a Unix-domain socket, remove an existing
socket at the same path so the bind is successful. This may affect
existing usage with respect to zopectl debug behavior, but will be
more predictable.


0.3.0 (2011-12-12)
------------------

- Added a simplified registration interface.


0.2.1 (2011-12-10)
------------------

Expand All @@ -25,18 +35,21 @@ Change History

- Add the "MORE" mode so commands can co-opt user interaction


0.1.2 (2008-09-15)
------------------

- Bugfix: The z3monitor server lacked a handle_close method, which
caused errors to get logged when users closed connections before
giving commands.


0.1.1 (2008-09-14)
------------------

- Bugfix: fixed and added test for regression in displaying tracebacks.


0.1.0 (2008-09-14)
------------------

Expand Down
9 changes: 8 additions & 1 deletion src/zc/monitor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""Zope 3 Monitor Server
"""

import errno, logging, traceback, socket
import errno, logging, os, stat, traceback, socket

import zope.component

Expand Down Expand Up @@ -91,6 +91,10 @@ def start(address):
elif isinstance(address, basestring):
#a unix domain socket string is passed
ourAddress = address
if os.path.exists(ourAddress):
m = os.stat(ourAddress)
if stat.S_ISSOCK(m.st_mode):
os.unlink(ourAddress)

try:
global last_listener
Expand All @@ -99,6 +103,9 @@ def start(address):
if e.args[0] == errno.EADDRINUSE:
# Don't kill the process just because somebody else has our port.
# This might be a zopectl debug or some other innocuous problem.
# (Existing Unix-domain sockets are removed before binding, so
# this doesn't work that way for those. Use a separate offline
# configuration in that case.)
logging.warning(
'unable to start zc.monitor server because the address %s '\
'is in use.',
Expand Down
15 changes: 11 additions & 4 deletions src/zc/monitor/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@
##############################################################################

import doctest
import sys
import unittest

def test_suite():
return doctest.DocFileSuite(
'README.txt',
optionflags=doctest.NORMALIZE_WHITESPACE,
)
suite = unittest.TestSuite([
doctest.DocFileSuite(
'README.txt',
optionflags=doctest.NORMALIZE_WHITESPACE,
),
])
if not sys.platform.lower().startswith('win'):
suite.addTest(doctest.DocFileSuite('unix-sockets.txt'))
return suite
46 changes: 46 additions & 0 deletions src/zc/monitor/unix-sockets.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
=========================
Using Unix-domain sockets
=========================

Passing a string to start causes it to bind to a Unix-domain socket.

Let's set up logging so we can see what's happening:

>>> import logging
>>> import os
>>> import stat
>>> import time
>>> import zc.monitor
>>> import zope.testing.loggingsupport

>>> loghandler = zope.testing.loggingsupport.InstalledHandler(
... None, level=logging.INFO)

Passing a path as the argument to start causes a Unix socket to be bound:

>>> path = "testing.sock"

>>> zc.monitor.start(path)
'testing.sock'

>>> m1 = os.stat(path)
>>> stat.S_ISSOCK(m1.st_mode)
True

Attempting to start the monitor at the same path again succeeds, but
causes a new socket to be created:

>>> zc.monitor.start(path)
'testing.sock'

>>> m2 = os.stat(path)
>>> stat.S_ISSOCK(m2.st_mode)
True

>>> m1.st_ino == m2.st_ino
False

Clean up:

>>> os.unlink(path)
>>> loghandler.uninstall()

0 comments on commit f46eeeb

Please sign in to comment.