Commit 966f7dfa authored by Hanno Schlichting's avatar Hanno Schlichting

flake8

parent 8e52f973
import sys, asyncore, time import asyncore
import time
_shutdown_phase = 0 _shutdown_phase = 0
_shutdown_timeout = 30 # seconds per phase _shutdown_timeout = 30 # seconds per phase
# The shutdown phase counts up from 0 to 4. # The shutdown phase counts up from 0 to 4.
# #
...@@ -23,7 +24,8 @@ _shutdown_timeout = 30 # seconds per phase ...@@ -23,7 +24,8 @@ _shutdown_timeout = 30 # seconds per phase
# of time that it has currently been in that phase. This method should return # of time that it has currently been in that phase. This method should return
# true if it does not yet want shutdown to proceed to the next phase. # true if it does not yet want shutdown to proceed to the next phase.
def shutdown(exit_code,fast = 0):
def shutdown(exit_code, fast=0):
global _shutdown_phase global _shutdown_phase
global _shutdown_timeout global _shutdown_timeout
if _shutdown_phase == 0: if _shutdown_phase == 0:
...@@ -38,6 +40,7 @@ def shutdown(exit_code,fast = 0): ...@@ -38,6 +40,7 @@ def shutdown(exit_code,fast = 0):
# enough, but still clean. # enough, but still clean.
_shutdown_timeout = 1.0 _shutdown_timeout = 1.0
def loop(): def loop():
# Run the main loop until someone calls shutdown() # Run the main loop until someone calls shutdown()
lifetime_loop() lifetime_loop()
...@@ -45,6 +48,7 @@ def loop(): ...@@ -45,6 +48,7 @@ def loop():
# loop to allow remaining requests to trickle away. # loop to allow remaining requests to trickle away.
graceful_shutdown_loop() graceful_shutdown_loop()
def lifetime_loop(): def lifetime_loop():
# The main loop. Stay in here until we need to shutdown # The main loop. Stay in here until we need to shutdown
map = asyncore.socket_map map = asyncore.socket_map
...@@ -52,7 +56,7 @@ def lifetime_loop(): ...@@ -52,7 +56,7 @@ def lifetime_loop():
while map and _shutdown_phase == 0: while map and _shutdown_phase == 0:
asyncore.poll(timeout, map) asyncore.poll(timeout, map)
def graceful_shutdown_loop(): def graceful_shutdown_loop():
# The shutdown loop. Allow various services to shutdown gradually. # The shutdown loop. Allow various services to shutdown gradually.
global _shutdown_phase global _shutdown_phase
...@@ -60,19 +64,19 @@ def graceful_shutdown_loop(): ...@@ -60,19 +64,19 @@ def graceful_shutdown_loop():
timeout = 1.0 timeout = 1.0
map = asyncore.socket_map map = asyncore.socket_map
while map and _shutdown_phase < 4: while map and _shutdown_phase < 4:
time_in_this_phase = time.time()-timestamp time_in_this_phase = time.time() - timestamp
veto = 0 veto = 0
for fd,obj in map.items(): for fd, obj in map.items():
try: try:
fn = getattr(obj,'clean_shutdown_control') fn = getattr(obj, 'clean_shutdown_control')
except AttributeError: except AttributeError:
pass pass
else: else:
try: try:
veto = veto or fn(_shutdown_phase,time_in_this_phase) veto = veto or fn(_shutdown_phase, time_in_this_phase)
except: except:
obj.handle_error() obj.handle_error()
if veto and time_in_this_phase<_shutdown_timeout: if veto and time_in_this_phase < _shutdown_timeout:
# Any open socket handler can veto moving on to the next shutdown # Any open socket handler can veto moving on to the next shutdown
# phase. (but not forever) # phase. (but not forever)
asyncore.poll(timeout, map) asyncore.poll(timeout, map)
...@@ -80,4 +84,3 @@ def graceful_shutdown_loop(): ...@@ -80,4 +84,3 @@ def graceful_shutdown_loop():
# No vetos? That is one step closer to shutting down # No vetos? That is one step closer to shutting down
_shutdown_phase += 1 _shutdown_phase += 1
timestamp = time.time() timestamp = time.time()
...@@ -12,13 +12,15 @@ ...@@ -12,13 +12,15 @@
############################################################################## ##############################################################################
"""Signal handling dispatcher.""" """Signal handling dispatcher."""
import sys, os import os
import sys
import signal import signal
from logging import getLogger from logging import getLogger
LOG = getLogger('SignalHandler') LOG = getLogger('SignalHandler')
class SignalHandler:
class SignalHandler(object):
def __init__(self): def __init__(self):
self.registry = {} self.registry = {}
...@@ -52,7 +54,8 @@ class SignalHandler: ...@@ -52,7 +54,8 @@ class SignalHandler:
for handler in self.registry.get(signum, []): for handler in self.registry.get(signum, []):
# Never let a bad handler prevent the standard signal # Never let a bad handler prevent the standard signal
# handlers from running. # handlers from running.
try: handler() try:
handler()
except SystemExit: except SystemExit:
# if we trap SystemExit, we can't restart # if we trap SystemExit, we can't restart
raise raise
...@@ -62,6 +65,7 @@ class SignalHandler: ...@@ -62,6 +65,7 @@ class SignalHandler:
_signals = None _signals = None
def get_signal_name(n): def get_signal_name(n):
"""Return the symbolic name for signal n. """Return the symbolic name for signal n.
......
...@@ -22,7 +22,6 @@ import Lifetime ...@@ -22,7 +22,6 @@ import Lifetime
from .threads import dump_threads from .threads import dump_threads
logger = logging.getLogger("Z2") logger = logging.getLogger("Z2")
if os.name == 'nt': if os.name == 'nt':
...@@ -37,11 +36,12 @@ if os.name == 'nt': ...@@ -37,11 +36,12 @@ if os.name == 'nt':
else: else:
from SignalHandler import SignalHandler from SignalHandler import SignalHandler
def shutdownFastHandler(): def shutdownFastHandler():
"""Shutdown cleanly on SIGTERM. This is registered first, """Shutdown cleanly on SIGTERM. This is registered first,
so it should be called after all other handlers.""" so it should be called after all other handlers."""
logger.info("Shutting down fast") logger.info("Shutting down fast")
Lifetime.shutdown(0,fast=1) Lifetime.shutdown(0, fast=1)
def shutdownHandler(): def shutdownHandler():
...@@ -50,6 +50,7 @@ def shutdownHandler(): ...@@ -50,6 +50,7 @@ def shutdownHandler():
logger.info("Shutting down") logger.info("Shutting down")
sys.exit(0) sys.exit(0)
def restartHandler(): def restartHandler():
"""Restart cleanly on SIGHUP. This is registered first, so it """Restart cleanly on SIGHUP. This is registered first, so it
should be called after all other SIGHUP handlers.""" should be called after all other SIGHUP handlers."""
...@@ -59,11 +60,11 @@ def restartHandler(): ...@@ -59,11 +60,11 @@ def restartHandler():
def showStacks(): def showStacks():
"""Dump a stracktrace of all threads on the console.""" """Dump a stracktrace of all threads on the console."""
print dump_threads() print(dump_threads())
sys.stdout.flush() sys.stdout.flush()
class LogfileReopenHandler: class LogfileReopenHandler(object):
"""Reopen log files on SIGUSR2. """Reopen log files on SIGUSR2.
This is registered first, so it should be called after all other This is registered first, so it should be called after all other
...@@ -77,12 +78,15 @@ class LogfileReopenHandler: ...@@ -77,12 +78,15 @@ class LogfileReopenHandler:
log.reopen() log.reopen()
logger.info("Log files reopened successfully") logger.info("Log files reopened successfully")
# On Windows, a 'reopen' is useless - the file can not be renamed # On Windows, a 'reopen' is useless - the file can not be renamed
# while open, so we perform a trivial 'rotate'. # while open, so we perform a trivial 'rotate'.
class LogfileRotateHandler: class LogfileRotateHandler(object):
"""Rotate log files on SIGUSR2. Only called on Windows. This is """
registered first, so it should be called after all other SIGUSR2 Rotate log files on SIGUSR2. Only called on Windows. This is
handlers.""" registered first, so it should be called after all other SIGUSR2
handlers.
"""
def __init__(self, loggers): def __init__(self, loggers):
self.loggers = [log for log in loggers if log is not None] self.loggers = [log for log in loggers if log is not None]
...@@ -95,6 +99,7 @@ class LogfileRotateHandler: ...@@ -95,6 +99,7 @@ class LogfileRotateHandler:
handler.rotate() handler.rotate()
logger.info("Log files rotation complete") logger.info("Log files rotation complete")
def registerZopeSignals(loggers): def registerZopeSignals(loggers):
from signal import SIGTERM, SIGINT from signal import SIGTERM, SIGINT
try: try:
...@@ -111,7 +116,7 @@ def registerZopeSignals(loggers): ...@@ -111,7 +116,7 @@ def registerZopeSignals(loggers):
mod_wsgi = True mod_wsgi = True
try: try:
from mod_wsgi import version from mod_wsgi import version # NOQA
except ImportError: except ImportError:
mod_wsgi = False mod_wsgi = False
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
# #
# One event is used per signal, and the event name is based on both the # One event is used per signal, and the event name is based on both the
# Zope process ID and the signal number. For example, assuming a process # Zope process ID and the signal number. For example, assuming a process
# ID of 123, a SIGINT handler would create an event called "Zope-123-2" # ID of 123, a SIGINT handler would create an event called "Zope-123-2"
# (as signal.SIGINT==2). The logfile reopen handler uses an event named # (as signal.SIGINT==2). The logfile reopen handler uses an event named
# "Zope-123-12" (as the logfile handler uses SIGUSR2, which == 12) # "Zope-123-12" (as the logfile handler uses SIGUSR2, which == 12)
...@@ -35,13 +35,14 @@ ...@@ -35,13 +35,14 @@
# NOTE: There is one huge semantic difference between these "signals" # NOTE: There is one huge semantic difference between these "signals"
# and signals on Unix. On Windows, the signals are delivered asynchronously # and signals on Unix. On Windows, the signals are delivered asynchronously
# to a thread inside this module. This thread calls the event handler # to a thread inside this module. This thread calls the event handler
# directly - there is no magic to switch the call back to the main thread. # directly - there is no magic to switch the call back to the main thread.
# If this is a problem (not currently, but likely later), one option may be # If this is a problem (not currently, but likely later), one option may be
# to add yet another asyncore handler - the thread in this module could # to add yet another asyncore handler - the thread in this module could
# then "post" the request to the main thread via this asyncore handler. # then "post" the request to the main thread via this asyncore handler.
import sys, os import os
import sys
import signal import signal
import threading import threading
import asyncore import asyncore
...@@ -62,7 +63,7 @@ import win32event ...@@ -62,7 +63,7 @@ import win32event
import ntsecuritycon import ntsecuritycon
import logging import logging
logger=logging.getLogger("WinSignalHandler") logger = logging.getLogger("WinSignalHandler")
# We simulate signals via win32 named events. This is the event name # We simulate signals via win32 named events. This is the event name
# prefix we use - the "signal number" is appended to this name. # prefix we use - the "signal number" is appended to this name.
...@@ -76,15 +77,16 @@ winver = sys.getwindowsversion() ...@@ -76,15 +77,16 @@ winver = sys.getwindowsversion()
if winver[0] >= 5 and winver[3] == 2: if winver[0] >= 5 and winver[3] == 2:
event_name_prefix = "Global\\" + event_name_prefix event_name_prefix = "Global\\" + event_name_prefix
def createEventSecurityObject(): def createEventSecurityObject():
# Create a security object giving World read/write access, # Create a security object giving World read/write access,
# but only "Owner" modify access. # but only "Owner" modify access.
sa = pywintypes.SECURITY_ATTRIBUTES() sa = pywintypes.SECURITY_ATTRIBUTES()
sidEveryone = pywintypes.SID() sidEveryone = pywintypes.SID()
sidEveryone.Initialize(ntsecuritycon.SECURITY_WORLD_SID_AUTHORITY,1) sidEveryone.Initialize(ntsecuritycon.SECURITY_WORLD_SID_AUTHORITY, 1)
sidEveryone.SetSubAuthority(0, ntsecuritycon.SECURITY_WORLD_RID) sidEveryone.SetSubAuthority(0, ntsecuritycon.SECURITY_WORLD_RID)
sidCreator = pywintypes.SID() sidCreator = pywintypes.SID()
sidCreator.Initialize(ntsecuritycon.SECURITY_CREATOR_SID_AUTHORITY,1) sidCreator.Initialize(ntsecuritycon.SECURITY_CREATOR_SID_AUTHORITY, 1)
sidCreator.SetSubAuthority(0, ntsecuritycon.SECURITY_CREATOR_OWNER_RID) sidCreator.SetSubAuthority(0, ntsecuritycon.SECURITY_CREATOR_OWNER_RID)
acl = pywintypes.ACL() acl = pywintypes.ACL()
...@@ -94,9 +96,10 @@ def createEventSecurityObject(): ...@@ -94,9 +96,10 @@ def createEventSecurityObject():
sa.SetSecurityDescriptorDacl(1, acl, 0) sa.SetSecurityDescriptorDacl(1, acl, 0)
return sa return sa
def wakeSelect(): def wakeSelect():
"""Interrupt a sleeping asyncore 'select' call""" """Interrupt a sleeping asyncore 'select' call"""
# What is the right thing to do here? # What is the right thing to do here?
# asyncore.close_all() works, but I fear that would # asyncore.close_all() works, but I fear that would
# prevent the poll based graceful cleanup code from working. # prevent the poll based graceful cleanup code from working.
# This seems to work :) # This seems to work :)
...@@ -104,7 +107,8 @@ def wakeSelect(): ...@@ -104,7 +107,8 @@ def wakeSelect():
if hasattr(obj, "pull_trigger"): if hasattr(obj, "pull_trigger"):
obj.pull_trigger() obj.pull_trigger()
class SignalHandler:
class SignalHandler(object):
def __init__(self): def __init__(self):
self.registry = {} self.registry = {}
...@@ -113,7 +117,7 @@ class SignalHandler: ...@@ -113,7 +117,7 @@ class SignalHandler:
self.shutdown_requested = False self.shutdown_requested = False
# Register a "console control handler" for Ctrl+C/Break notification. # Register a "console control handler" for Ctrl+C/Break notification.
SetConsoleCtrlHandler(consoleCtrlHandler) SetConsoleCtrlHandler(consoleCtrlHandler)
# Start the thread that is watching for events. # Start the thread that is watching for events.
thread = threading.Thread(target=self.signalCheckerThread) thread = threading.Thread(target=self.signalCheckerThread)
# If something goes terribly wrong, don't wait for this thread! # If something goes terribly wrong, don't wait for this thread!
...@@ -126,12 +130,7 @@ class SignalHandler: ...@@ -126,12 +130,7 @@ class SignalHandler:
logger.debug("signal handler shutdown starting.") logger.debug("signal handler shutdown starting.")
self.shutdown_requested = 1 self.shutdown_requested = 1
win32event.SetEvent(self.admin_event_handle) win32event.SetEvent(self.admin_event_handle)
# sadly, this can deadlock at shutdown when Ctrl+C is used self.signal_thread.join(5) # should never block for long!
# (although not then the event is used to trigger shutdown)
# at least in build 204. Further updates as they come to hand...
# Remove the Windows control handler
#SetConsoleCtrlHandler(consoleCtrlHandler, 0)
self.signal_thread.join(5) # should never block for long!
self.registry = None self.registry = None
self.event_handles = None self.event_handles = None
...@@ -139,7 +138,7 @@ class SignalHandler: ...@@ -139,7 +138,7 @@ class SignalHandler:
logger.debug("signal handler shutdown complete.") logger.debug("signal handler shutdown complete.")
def consoleCtrlHandler(self, ctrlType): def consoleCtrlHandler(self, ctrlType):
"""Called by Windows on a new thread whenever a console control """Called by Windows on a new thread whenever a console control
event is raised.""" event is raised."""
logger.debug("Windows control event %d" % ctrlType) logger.debug("Windows control event %d" % ctrlType)
sig = None sig = None
...@@ -153,13 +152,13 @@ class SignalHandler: ...@@ -153,13 +152,13 @@ class SignalHandler:
# CTRL_CLOSE_EVENT gives us 5 seconds before displaying # CTRL_CLOSE_EVENT gives us 5 seconds before displaying
# the "End process" dialog - so treat as 'fast' # the "End process" dialog - so treat as 'fast'
sig = signal.SIGTERM sig = signal.SIGTERM
elif ctrlType in (win32con.CTRL_LOGOFF_EVENT, elif ctrlType in (win32con.CTRL_LOGOFF_EVENT,
win32con.CTRL_SHUTDOWN_EVENT): win32con.CTRL_SHUTDOWN_EVENT):
# MSDN says: # MSDN says:
# "Note that this signal is received only by services. # "Note that this signal is received only by services.
# Interactive applications are terminated at logoff, so # Interactive applications are terminated at logoff, so
# they are not present when the system sends this signal." # they are not present when the system sends this signal."
# We can therefore ignore it (our service framework # We can therefore ignore it (our service framework
# manages shutdown in this case) # manages shutdown in this case)
pass pass
else: else:
...@@ -169,9 +168,9 @@ class SignalHandler: ...@@ -169,9 +168,9 @@ class SignalHandler:
# that we don't wake the select loop until after the shutdown # that we don't wake the select loop until after the shutdown
# flags have been set. # flags have been set.
result = 0 result = 0
if sig is not None and self.registry.has_key(sig): if sig is not None and sig in self.registry:
self.signalHandler(sig, None) self.signalHandler(sig, None)
result = 1 # don't call other handlers. result = 1 # don't call other handlers.
return result return result
def signalCheckerThread(self): def signalCheckerThread(self):
...@@ -210,7 +209,8 @@ class SignalHandler: ...@@ -210,7 +209,8 @@ class SignalHandler:
# Let the worker thread know there is a new handle. # Let the worker thread know there is a new handle.
win32event.SetEvent(self.admin_event_handle) win32event.SetEvent(self.admin_event_handle)
signame = get_signal_name(signum) signame = get_signal_name(signum)
logger.debug("Installed sighandler for %s (%s)" % (signame, event_name)) logger.debug(
"Installed sighandler for %s (%s)" % (signame, event_name))
items.insert(0, handler) items.insert(0, handler)
def getRegisteredSignals(self): def getRegisteredSignals(self):
...@@ -226,20 +226,23 @@ class SignalHandler: ...@@ -226,20 +226,23 @@ class SignalHandler:
for handler in self.registry.get(signum, []): for handler in self.registry.get(signum, []):
# Never let a bad handler prevent the standard signal # Never let a bad handler prevent the standard signal
# handlers from running. # handlers from running.
try: handler() try:
except SystemExit, rc: handler()
# On Unix, signals are delivered to the main thread, so a except SystemExit as rc:
# On Unix, signals are delivered to the main thread, so a
# SystemExit does the right thing. On Windows, we are on # SystemExit does the right thing. On Windows, we are on
# our own thread, so throwing SystemExit there isn't a great # our own thread, so throwing SystemExit there isn't a great
# idea. Just shutdown the main loop. # idea. Just shutdown the main loop.
logger.debug("Trapped SystemExit(%s) - doing Lifetime shutdown" % (rc,)) logger.debug(
"Trapped SystemExit(%s) - doing Lifetime shutdown" % rc)
Lifetime.shutdown(rc) Lifetime.shutdown(rc)
except: except:
logger.exception("A handler for %s failed!'" % signame) logger.exception("A handler for %s failed!'" % signame)
wakeSelect() # trigger a walk around the Lifetime loop. wakeSelect() # trigger a walk around the Lifetime loop.
_signals = None _signals = None
def get_signal_name(n): def get_signal_name(n):
"""Return the symbolic name for signal n. """Return the symbolic name for signal n.
...@@ -257,19 +260,20 @@ def get_signal_name(n): ...@@ -257,19 +260,20 @@ def get_signal_name(n):
_signals[v] = k _signals[v] = k
# extra ones that aren't (weren't?) in Windows. # extra ones that aren't (weren't?) in Windows.
for name, val in ("SIGHUP", 1), ("SIGUSR1", 10), ("SIGUSR2", 12): for name, val in ("SIGHUP", 1), ("SIGUSR1", 10), ("SIGUSR2", 12):
if not _signals.has_key(name): if name not in _signals:
_signals[val] = name _signals[val] = name
return _signals.get(n, 'signal %d' % n) return _signals.get(n, 'signal %d' % n)
# The win32 ConsoleCtrlHandler
def consoleCtrlHandler(ctrlType): def consoleCtrlHandler(ctrlType):
# The win32 ConsoleCtrlHandler
return SignalHandler.consoleCtrlHandler(ctrlType) return SignalHandler.consoleCtrlHandler(ctrlType)
# The SignalHandler is actually a singleton. # The SignalHandler is actually a singleton.
SignalHandler = SignalHandler() SignalHandler = SignalHandler()
# Need to be careful at shutdown - the 'signal watcher' thread which triggers # Need to be careful at shutdown - the 'signal watcher' thread which triggers
# the shutdown may still be running when the main thread terminates and # the shutdown may still be running when the main thread terminates and
# Python starts cleaning up. # Python starts cleaning up.
atexit.register(SignalHandler.shutdown) atexit.register(SignalHandler.shutdown)
"""
Signals package __init__.py
"""
...@@ -26,10 +26,10 @@ def dump_threads(): ...@@ -26,10 +26,10 @@ def dump_threads():
request = f.f_locals.get('request') request = f.f_locals.get('request')
if request is not None: if request is not None:
reqinfo += (request.get('REQUEST_METHOD', '') + ' ' + reqinfo += (request.get('REQUEST_METHOD', '') + ' ' +
request.get('PATH_INFO', '')) request.get('PATH_INFO', ''))
qs = request.get('QUERY_STRING') qs = request.get('QUERY_STRING')
if qs: if qs:
reqinfo += '?'+qs reqinfo += '?' + qs
break break
f = f.f_back f = f.f_back
if reqinfo: if reqinfo:
...@@ -37,8 +37,8 @@ def dump_threads(): ...@@ -37,8 +37,8 @@ def dump_threads():
output = StringIO() output = StringIO()
traceback.print_stack(frame, file=output) traceback.print_stack(frame, file=output)
res.append("Thread %s%s:\n%s" % res.append(
(thread_id, reqinfo, output.getvalue())) "Thread %s%s:\n%s" % (thread_id, reqinfo, output.getvalue()))
frames = None frames = None
res.append("End of dump") res.append("End of dump")
......
...@@ -45,7 +45,7 @@ def get_starter(): ...@@ -45,7 +45,7 @@ def get_starter():
return UnixZopeStarter() return UnixZopeStarter()
class ZopeStarter: class ZopeStarter(object):
"""This is a class which starts a Zope server. """This is a class which starts a Zope server.
Making it a class makes it easier to test. Making it a class makes it easier to test.
...@@ -72,7 +72,6 @@ class ZopeStarter: ...@@ -72,7 +72,6 @@ class ZopeStarter:
def setConfiguration(self, cfg): def setConfiguration(self, cfg):
self.cfg = cfg self.cfg = cfg
def sendEvents(self): def sendEvents(self):
notify(ProcessStarting()) notify(ProcessStarting())
...@@ -174,16 +173,14 @@ class ZopeStarter: ...@@ -174,16 +173,14 @@ class ZopeStarter:
'The locale module could not be imported.\n' 'The locale module could not be imported.\n'
'To use localization options, you must ensure\n' 'To use localization options, you must ensure\n'
'that the locale module is compiled into your\n' 'that the locale module is compiled into your\n'
'Python installation.' 'Python installation.')
)
try: try:
locale.setlocale(locale.LC_ALL, locale_id) locale.setlocale(locale.LC_ALL, locale_id)
except: except:
raise ZConfig.ConfigurationError( raise ZConfig.ConfigurationError(
'The specified locale "%s" is not supported by your' 'The specified locale "%s" is not supported by your'
'system.\nSee your operating system documentation for ' 'system.\nSee your operating system documentation for '
'more\ninformation on locale support.' % locale_id 'more\ninformation on locale support.' % locale_id)
)
def setupZServer(self): def setupZServer(self):
# Increase the number of threads # Increase the number of threads
...@@ -197,7 +194,8 @@ class ZopeStarter: ...@@ -197,7 +194,8 @@ class ZopeStarter:
# This one has the delayed listening feature # This one has the delayed listening feature
if not server.fast_listen: if not server.fast_listen:
server.fast_listen = True server.fast_listen = True
server.listen(1024) # same value as defined in medusa.http_server.py # same value as defined in medusa.http_server.py
server.listen(1024)
def setupServers(self): def setupServers(self):
socket_err = ( socket_err = (
...@@ -205,17 +203,16 @@ class ZopeStarter: ...@@ -205,17 +203,16 @@ class ZopeStarter:
'This may mean that your user does not have permission to ' 'This may mean that your user does not have permission to '
'bind to the port which the server is trying to use or the ' 'bind to the port which the server is trying to use or the '
'port may already be in use by another application. ' 'port may already be in use by another application. '
'(%s)' '(%s)')
)
servers = [] servers = []
for server in self.cfg.servers: for server in self.cfg.servers:
# create the server from the server factory # create the server from the server factory
# set up in the config # set up in the config
try: try:
servers.append(server.create()) servers.append(server.create())
except socket.error,e: except socket.error as e:
raise ZConfig.ConfigurationError(socket_err raise ZConfig.ConfigurationError(
% (server.servertype(),e[1])) socket_err % (server.servertype(), e[1]))
self.cfg.servers = servers self.cfg.servers = servers
def dropPrivileges(self): def dropPrivileges(self):
...@@ -372,7 +369,7 @@ def dropPrivileges(cfg): ...@@ -372,7 +369,7 @@ def dropPrivileges(cfg):
import pwd import pwd
effective_user = cfg.effective_user effective_user = cfg.effective_user
if effective_user is None: if effective_user is None:
msg = ('A user was not specified to setuid to; fix this to ' msg = ('A user was not specified to setuid to; fix this to '
'start as root (change the effective-user directive ' 'start as root (change the effective-user directive '
...@@ -413,15 +410,15 @@ def dropPrivileges(cfg): ...@@ -413,15 +410,15 @@ def dropPrivileges(cfg):
os.setuid(uid) os.setuid(uid)
logger.info('Set effective user to "%s"' % effective_user) logger.info('Set effective user to "%s"' % effective_user)
return 1 # for unit testing purposes return 1 # for unit testing purposes
# DM 2004-11-24: added
def _name2Ips(host, isIp_=compile(r'(\d+\.){3}').match): def _name2Ips(host, isIp_=compile(r'(\d+\.){3}').match):
'''map a name *host* to the sequence of its ip addresses; '''map a name *host* to the sequence of its ip addresses;
use *host* itself (as sequence) if it already is an ip address. use *host* itself (as sequence) if it already is an ip address.
Thus, if only a specific interface on a host is trusted, Thus, if only a specific interface on a host is trusted,
identify it by its ip (and not the host name). identify it by its ip (and not the host name).
''' '''
if isIp_(host): return [host] if isIp_(host):
return [host]
return gethostbyaddr(host)[2] return gethostbyaddr(host)[2]
...@@ -34,6 +34,7 @@ from App.config import getConfiguration, setConfiguration ...@@ -34,6 +34,7 @@ from App.config import getConfiguration, setConfiguration
TEMPNAME = tempfile.mktemp() TEMPNAME = tempfile.mktemp()
TEMPPRODUCTS = os.path.join(TEMPNAME, "Products") TEMPPRODUCTS = os.path.join(TEMPNAME, "Products")
def getSchema(): def getSchema():
startup = os.path.dirname(Zope2.Startup.__file__) startup = os.path.dirname(Zope2.Startup.__file__)
schemafile = os.path.join(startup, 'zopeschema.xml') schemafile = os.path.join(startup, 'zopeschema.xml')
...@@ -45,10 +46,11 @@ def getSchema(): ...@@ -45,10 +46,11 @@ def getSchema():
logger_states = {} logger_states = {}
for name in (None, 'trace', 'access'): for name in (None, 'trace', 'access'):
logger = logging.getLogger(name) logger = logging.getLogger(name)
logger_states[name] = {'level':logger.level, logger_states[name] = {'level': logger.level,
'propagate':logger.propagate, 'propagate': logger.propagate,
'handlers':logger.handlers, 'handlers': logger.handlers,
'filters':logger.filters} 'filters': logger.filters}
class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...@@ -94,7 +96,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -94,7 +96,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
try: try:
os.mkdir(TEMPNAME) os.mkdir(TEMPNAME)
os.mkdir(TEMPPRODUCTS) os.mkdir(TEMPPRODUCTS)
except OSError, why: except OSError as why:
if why == 17: if why == 17:
# already exists # already exists
pass pass
...@@ -110,10 +112,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -110,10 +112,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
conf = self.load_config_text(""" conf = self.load_config_text("""
instancehome <<INSTANCE_HOME>> instancehome <<INSTANCE_HOME>>
locale en_GB""") locale en_GB""")
except ZConfig.DataConversionError, e: except ZConfig.DataConversionError as e:
# Skip this test if we don't have support. # Skip this test if we don't have support.
if e.message.startswith( if e.message.startswith(
'The specified locale "en_GB" is not supported'): 'The specified locale "en_GB" is not supported'):
return return
raise raise
starter = self.get_starter(conf) starter = self.get_starter(conf)
...@@ -146,16 +148,12 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -146,16 +148,12 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
# startup handler should take on the level of the event log handler # startup handler should take on the level of the event log handler
# with the lowest level # with the lowest level
logger = starter.event_logger logger = starter.event_logger
self.assertEqual(starter.startup_handler.level, 15) # 15 is BLATHER self.assertEqual(starter.startup_handler.level, 15) # 15 is BLATHER
self.assert_(starter.startup_handler in logger.handlers) self.assert_(starter.startup_handler in logger.handlers)
self.assertEqual(logger.level, 15) self.assertEqual(logger.level, 15)
# We expect a debug handler and the startup handler: # We expect a debug handler and the startup handler:
self.assertEqual(len(logger.handlers), 2) self.assertEqual(len(logger.handlers), 2)
# XXX need to check that log messages get written to
# sys.stderr, not that the stream identity for the startup
# handler matches
#self.assertEqual(starter.startup_handler.stream, sys.stderr)
conf = self.load_config_text(""" conf = self.load_config_text("""
instancehome <<INSTANCE_HOME>> instancehome <<INSTANCE_HOME>>
debug-mode off debug-mode off
...@@ -168,10 +166,6 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -168,10 +166,6 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
</eventlog>""") </eventlog>""")
starter = self.get_starter(conf) starter = self.get_starter(conf)
starter.setupInitialLogging() starter.setupInitialLogging()
# XXX need to check that log messages get written to
# sys.stderr, not that the stream identity for the startup
# handler matches
#self.assertNotEqual(starter.startup_handler.stream, sys.stderr)
def testSetupZServerThreads(self): def testSetupZServerThreads(self):
conf = self.load_config_text(""" conf = self.load_config_text("""
...@@ -193,7 +187,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -193,7 +187,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
</http-server> </http-server>
<ftp-server> <ftp-server>
address %(ftp)s address %(ftp)s
</ftp-server>""" % dict(http=port, ftp=port+1) </ftp-server>""" % dict(http=port, ftp=port + 1)
) )
starter = self.get_starter(conf) starter = self.get_starter(conf)
# do the job the 'handler' would have done (call prepare) # do the job the 'handler' would have done (call prepare)
...@@ -207,7 +201,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -207,7 +201,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
self.assertEqual(conf.servers[1].__class__, self.assertEqual(conf.servers[1].__class__,
ZServer.FTPServer) ZServer.FTPServer)
finally: finally:
del conf.servers # should release servers del conf.servers # should release servers
pass pass
def testDropPrivileges(self): def testDropPrivileges(self):
...@@ -216,8 +210,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -216,8 +210,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
if os.name != 'posix': if os.name != 'posix':
return return
_old_getuid = os.getuid _old_getuid = os.getuid
def _return0(): def _return0():
return 0 return 0
def make_starter(conf): def make_starter(conf):
# remove the debug handler, since we don't want junk on # remove the debug handler, since we don't want junk on
# stderr for the tests # stderr for the tests
...@@ -292,8 +288,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -292,8 +288,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
self.assertEqual(logger.level, logging.INFO) self.assertEqual(logger.level, logging.INFO)
l = open(os.path.join(TEMPNAME, 'event.log')).read() l = open(os.path.join(TEMPNAME, 'event.log')).read()
self.assertTrue(l.find('hello') > -1) self.assertTrue(l.find('hello') > -1)
self.assertTrue(os.path.exists(os.path.join(TEMPNAME, 'Z2.log'))) self.assertTrue(
self.assertTrue(os.path.exists(os.path.join(TEMPNAME,'trace.log'))) os.path.exists(os.path.join(TEMPNAME, 'Z2.log')))
self.assertTrue(
os.path.exists(os.path.join(TEMPNAME, 'trace.log')))
finally: finally:
for name in ('event.log', 'Z2.log', 'trace.log'): for name in ('event.log', 'Z2.log', 'trace.log'):
try: try:
...@@ -355,12 +353,11 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -355,12 +353,11 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
conf = self.load_config_text(""" conf = self.load_config_text("""
instancehome <<INSTANCE_HOME>> instancehome <<INSTANCE_HOME>>
python-check-interval %d python-check-interval %d
""" % newcheckinterval """ % newcheckinterval)
)
try: try:
starter = self.get_starter(conf) starter = self.get_starter(conf)
starter.setupInterpreter() starter.setupInterpreter()
self.assertEqual( sys.getcheckinterval() , newcheckinterval ) self.assertEqual(sys.getcheckinterval(), newcheckinterval)
finally: finally:
sys.setcheckinterval(oldcheckinterval) sys.setcheckinterval(oldcheckinterval)
...@@ -369,7 +366,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -369,7 +366,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
try: try:
os.mkdir(TEMPNAME) os.mkdir(TEMPNAME)
os.mkdir(TEMPPRODUCTS) os.mkdir(TEMPPRODUCTS)
except OSError, why: except OSError as why:
if why == errno.EEXIST: if why == errno.EEXIST:
# already exists # already exists
pass pass
...@@ -392,7 +389,3 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase): ...@@ -392,7 +389,3 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
except: except:
pass pass
setConfiguration(old_config) setConfiguration(old_config)
def test_suite():
return unittest.makeSuite(ZopeStarterTestCase)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment