K
kkt49
# vim: et sw=4 ts=8 sts
from wxPython.wx import *
import sys, os, time
import pywintypes
import win32serviceutil
import win32service
import win32event
import win32process
ID_ABOUT = 101
ID_EXIT = 102
# the max seconds we're allowed to spend backing off
BACKOFF_MAX = 300
# if the process runs successfully for more than BACKOFF_CLEAR_TIME
# seconds, we reset the backoff stats to their initial values
BACKOFF_CLEAR_TIME = 30
# the initial backoff interval (the amount of time we wait to restart
# a dead process)
BACKOFF_INITIAL_INTERVAL = 5
class Service(win32serviceutil.ServiceFramework):
""" A class representing a Windows NT service that can manage an
instance-home-based Zope/ZEO/ZRS processes """
# The comment below is mostly irrelevant if you're running a
standalone
# SchoolBell server, I think. -TEH
# The PythonService model requires that an actual on-disk class
declaration
# represent a single service. Thus, the below definition of
start_cmd,
# must be overridden in a subclass in a file within the instance
home for
# each instance. The below-defined start_cmd (and
_svc_display_name_
# and _svc_name_) are just examples.
# To use this script with SchoolTool, just replace "SchoolBell"
# with "SchoolTool" in the variables below.
# You'll also need to change 'Python24' to 'Python23' if that's
# what you've got. -TEH
#cmd_str = os.environ["moin_service"]
#_svc_name_ = r'moin_service'
#_svc_display_name_ = r'moin_service'
#start_cmd = r"c:\mmde\moin.exe"
info = ['', '', '']
def __init__(self):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]
win32serviceutil.ServiceFramework.__init__(self)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()
def __init__(self, args):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]
win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()
def redirectOutput(self):
#pass
sys.stdout.close()
sys.stderr.close()
sys.stdout = NullOutput()
sys.stderr = NullOutput()
def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop
process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# TODO: This TerminateProcess call doesn't make much sense:
it's
# doing a hard kill _first_, never giving the process a chance
to
# shut down cleanly. Compare to current Zope2 service code,
which
# uses Windows events to give the process a chance to shut down
# cleanly, doing a hard kill only if that doesn't succeed.
# stop the process if necessary
try:
win32process.TerminateProcess(self.hZope, 0)
except pywintypes.error:
# the process may already have been terminated
pass
# And set my event.
win32event.SetEvent(self.hWaitStop)
# SvcStop only gets triggered when the user explictly stops (or
restarts)
# the service. To shut the service down cleanly when Windows is
shutting
# down, we also need to hook SvcShutdown.
SvcShutdown = SvcStop
def createProcess(self, cmd):
return win32process.CreateProcess(
None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO())
def SvcDoRun(self):
# indicate to Zope that the process is daemon managed
(restartable)
# os.environ['ZMANAGED'] = '1'
# daemon behavior: we want to to restart the process if it
# dies, but if it dies too many times, we need to give up.
# we use a simple backoff algorithm to determine whether
# we should try to restart a dead process: for each
# time the process dies unexpectedly, we wait some number of
# seconds to restart it, as determined by the backoff interval,
# which doubles each time the process dies. if we exceed
# BACKOFF_MAX seconds in cumulative backoff time, we give up.
# at any time if we successfully run the process for more thab
# BACKOFF_CLEAR_TIME seconds, the backoff stats are reset.
# the initial number of seconds between process start attempts
backoff_interval = BACKOFF_INITIAL_INTERVAL
# the cumulative backoff seconds counter
backoff_cumulative = 0
import servicemanager
# log a service started message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ' (%s)' % self._svc_display_name_))
while 1:
start_time = time.time()
info = self.createProcess(self.start_cmd)
self.hZope = info[0] # the pid
if backoff_interval > BACKOFF_INITIAL_INTERVAL:
# if we're in a backoff state, log a message about
# starting a new process
servicemanager.LogInfoMsg(
'%s (%s): recovering from died process, new process
'
'started' % (self._svc_name_,
self._svc_display_name_)
)
rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE)
if rc == win32event.WAIT_OBJECT_0:
# user sent a stop service request
self.SvcStop()
break
else:
# user did not send a service stop request, but
# the process died; this may be an error condition
status = win32process.GetExitCodeProcess(self.hZope)
if status == 0:
# the user shut the process down from the web
# interface (or it otherwise exited cleanly)
break
else:
# this was an abormal shutdown. if we can, we want
to
# restart the process but if it seems hopeless,
# don't restart an infinite number of times.
if backoff_cumulative > BACKOFF_MAX:
# it's hopeless
servicemanager.LogErrorMsg(
'%s (%s): process could not be restarted due
to max '
'restart attempts exceeded' % (
self._svc_display_name_, self._svc_name_
))
self.SvcStop()
break
servicemanager.LogWarningMsg(
'%s (%s): process died unexpectedly. Will
attempt '
'restart after %s seconds.' % (
self._svc_name_, self._svc_display_name_,
backoff_interval
)
)
# if BACKOFF_CLEAR_TIME seconds have elapsed since
we last
# started the process, reset the backoff interval
# and the cumulative backoff time to their original
# states
if time.time() - start_time > BACKOFF_CLEAR_TIME:
backoff_interval = BACKOFF_INITIAL_INTERVAL
backoff_cumulative = 0
# we sleep for the backoff interval. since this is
async
# code, it would be better done by sending and
# catching a timed event (a service
# stop request will need to wait for us to stop
sleeping),
# but this works well enough for me.
time.sleep(backoff_interval)
# update backoff_cumulative with the time we spent
# backing off.
backoff_cumulative = backoff_cumulative +
backoff_interval
# bump the backoff interval up by 2* the last
interval
backoff_interval = backoff_interval * 2
# loop and try to restart the process
# log a service stopped message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ' (%s) ' % self._svc_display_name_))
class NullOutput:
"""A stdout / stderr replacement that discards everything."""
def noop(self, *args, **kw):
pass
write = writelines = close = seek = flush = truncate = noop
def __iter__(self):
return self
def next(self):
raise StopIteration
def isatty(self):
return False
def tell(self):
return 0
def read(self, *args, **kw):
return ''
readline = read
def readlines(self, *args, **kw):
return []
class MyFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title, wxDefaultPosition,
wxSize(200, 150))
self.CreateStatusBar()
self.SetStatusText("This is the statusbar")
menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this
program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wxMenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
# 서비스명
servicenameText = wxStaticText(self, -1, "Service Name")
self.servicenameCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 서비스로 ì‹¤í–‰í• ëª…ë ¹
cmdText = wxStaticText(self, -1, "Service command")
self.cmdCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 실행 버튼
installButton = wxButton(self, -1, label="Install", size=(80,
-1))
removeButton = wxButton(self, -1, label="Remove", size=(80,
-1))
startButton = wxButton(self, -1, label="Start", size=(80, -1))
stopButton = wxButton(self, -1, label="Stop", size=(80, -1))
installButton.Bind(EVT_BUTTON, self.onInstallButtonClick)
removeButton.Bind(EVT_BUTTON, self.onRemoveButtonClick)
startButton.Bind(EVT_BUTTON, self.onStartButtonClick)
stopButton.Bind(EVT_BUTTON, self.onStopButtonClick)
# Sizer 구성
sizer = wxFlexGridSizer(rows=2, cols=2, hgap=10, vgap=5)
sizer.Add(servicenameText) # (0, 0)
sizer.Add(self.servicenameCtrl) # (0, 1)
sizer.Add(cmdText) # (1, 0)
sizer.Add(self.cmdCtrl) # (1, 1)
sizer.Add(installButton) # (2, 0)
sizer.Add(removeButton) # (2, 1)
sizer.Add(startButton) # (3, 0)
sizer.Add(stopButton) # (3, 1)
border = wxBoxSizer()
border.Add(sizer, 0, wxALL, 10)
self.SetSizerAndFit(border)
self.Fit()
def onInstallButtonClick(self, event):
Service.info[0] = self.servicenameCtrl.GetValue()
Service.info[1] = self.servicenameCtrl.GetValue()
Service.info[2] = self.cmdCtrl.GetValue()
#Service._svc_name_ = self.servicenameCtrl.GetValue()
#Service._svc_display_name_ = self.servicenameCtrl.GetValue()
#Service.start_cmd = self.cmdCtrl.GetValue()
#win32serviceutil.HandleCommandLine(Service)
win32serviceutil.InstallService(
win32serviceutil.GetServiceClassString(Service),
self.servicenameCtrl.GetValue(),
self.servicenameCtrl.GetValue()
)
def onRemoveButtonClick(self, event):
win32serviceutil.RemoveService(self.servicenameCtrl.GetValue())
def onStartButtonClick(self, event):
win32serviceutil.StartService(self.servicenameCtrl.GetValue())
def onStopButtonClick(self, event):
win32serviceutil.StopService(self.servicenameCtrl.GetValue())
#def onOkButtonClick(self, event):
# Service._svc_name_ = self.servicenameCtrl.GetValue()
# Service._svc_display_name_ = self.servicenameCtrl.GetValue()
# Service.start_cmd = (self.cmdCtrl.GetValue())
# sys.argv.append(self.argsCtrl.GetValue())
# win32serviceutil.HandleCommandLine(Service)
class MyApp(wxApp):
def OnInit(self):
frame = MyFrame(NULL, -1, "Hello from wxPython")
frame.servicenameCtrl.SetValue(r"moin_service")
frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")
#frame.argsCtrl.SetValue("stop")
Service.info[0] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[1] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[2] = frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")
frame.Show(true)
self.SetTopWindow(frame)
return true
if __name__ == '__main__':
app = MyApp(0)
app.MainLoop()
from wxPython.wx import *
import sys, os, time
import pywintypes
import win32serviceutil
import win32service
import win32event
import win32process
ID_ABOUT = 101
ID_EXIT = 102
# the max seconds we're allowed to spend backing off
BACKOFF_MAX = 300
# if the process runs successfully for more than BACKOFF_CLEAR_TIME
# seconds, we reset the backoff stats to their initial values
BACKOFF_CLEAR_TIME = 30
# the initial backoff interval (the amount of time we wait to restart
# a dead process)
BACKOFF_INITIAL_INTERVAL = 5
class Service(win32serviceutil.ServiceFramework):
""" A class representing a Windows NT service that can manage an
instance-home-based Zope/ZEO/ZRS processes """
# The comment below is mostly irrelevant if you're running a
standalone
# SchoolBell server, I think. -TEH
# The PythonService model requires that an actual on-disk class
declaration
# represent a single service. Thus, the below definition of
start_cmd,
# must be overridden in a subclass in a file within the instance
home for
# each instance. The below-defined start_cmd (and
_svc_display_name_
# and _svc_name_) are just examples.
# To use this script with SchoolTool, just replace "SchoolBell"
# with "SchoolTool" in the variables below.
# You'll also need to change 'Python24' to 'Python23' if that's
# what you've got. -TEH
#cmd_str = os.environ["moin_service"]
#_svc_name_ = r'moin_service'
#_svc_display_name_ = r'moin_service'
#start_cmd = r"c:\mmde\moin.exe"
info = ['', '', '']
def __init__(self):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]
win32serviceutil.ServiceFramework.__init__(self)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()
def __init__(self, args):
self._svc_name = info[0]
self._svc_display_name_ = info[1]
self.start_cmd = info[2]
win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.redirectOutput()
def redirectOutput(self):
#pass
sys.stdout.close()
sys.stderr.close()
sys.stdout = NullOutput()
sys.stderr = NullOutput()
def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop
process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# TODO: This TerminateProcess call doesn't make much sense:
it's
# doing a hard kill _first_, never giving the process a chance
to
# shut down cleanly. Compare to current Zope2 service code,
which
# uses Windows events to give the process a chance to shut down
# cleanly, doing a hard kill only if that doesn't succeed.
# stop the process if necessary
try:
win32process.TerminateProcess(self.hZope, 0)
except pywintypes.error:
# the process may already have been terminated
pass
# And set my event.
win32event.SetEvent(self.hWaitStop)
# SvcStop only gets triggered when the user explictly stops (or
restarts)
# the service. To shut the service down cleanly when Windows is
shutting
# down, we also need to hook SvcShutdown.
SvcShutdown = SvcStop
def createProcess(self, cmd):
return win32process.CreateProcess(
None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO())
def SvcDoRun(self):
# indicate to Zope that the process is daemon managed
(restartable)
# os.environ['ZMANAGED'] = '1'
# daemon behavior: we want to to restart the process if it
# dies, but if it dies too many times, we need to give up.
# we use a simple backoff algorithm to determine whether
# we should try to restart a dead process: for each
# time the process dies unexpectedly, we wait some number of
# seconds to restart it, as determined by the backoff interval,
# which doubles each time the process dies. if we exceed
# BACKOFF_MAX seconds in cumulative backoff time, we give up.
# at any time if we successfully run the process for more thab
# BACKOFF_CLEAR_TIME seconds, the backoff stats are reset.
# the initial number of seconds between process start attempts
backoff_interval = BACKOFF_INITIAL_INTERVAL
# the cumulative backoff seconds counter
backoff_cumulative = 0
import servicemanager
# log a service started message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ' (%s)' % self._svc_display_name_))
while 1:
start_time = time.time()
info = self.createProcess(self.start_cmd)
self.hZope = info[0] # the pid
if backoff_interval > BACKOFF_INITIAL_INTERVAL:
# if we're in a backoff state, log a message about
# starting a new process
servicemanager.LogInfoMsg(
'%s (%s): recovering from died process, new process
'
'started' % (self._svc_name_,
self._svc_display_name_)
)
rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE)
if rc == win32event.WAIT_OBJECT_0:
# user sent a stop service request
self.SvcStop()
break
else:
# user did not send a service stop request, but
# the process died; this may be an error condition
status = win32process.GetExitCodeProcess(self.hZope)
if status == 0:
# the user shut the process down from the web
# interface (or it otherwise exited cleanly)
break
else:
# this was an abormal shutdown. if we can, we want
to
# restart the process but if it seems hopeless,
# don't restart an infinite number of times.
if backoff_cumulative > BACKOFF_MAX:
# it's hopeless
servicemanager.LogErrorMsg(
'%s (%s): process could not be restarted due
to max '
'restart attempts exceeded' % (
self._svc_display_name_, self._svc_name_
))
self.SvcStop()
break
servicemanager.LogWarningMsg(
'%s (%s): process died unexpectedly. Will
attempt '
'restart after %s seconds.' % (
self._svc_name_, self._svc_display_name_,
backoff_interval
)
)
# if BACKOFF_CLEAR_TIME seconds have elapsed since
we last
# started the process, reset the backoff interval
# and the cumulative backoff time to their original
# states
if time.time() - start_time > BACKOFF_CLEAR_TIME:
backoff_interval = BACKOFF_INITIAL_INTERVAL
backoff_cumulative = 0
# we sleep for the backoff interval. since this is
async
# code, it would be better done by sending and
# catching a timed event (a service
# stop request will need to wait for us to stop
sleeping),
# but this works well enough for me.
time.sleep(backoff_interval)
# update backoff_cumulative with the time we spent
# backing off.
backoff_cumulative = backoff_cumulative +
backoff_interval
# bump the backoff interval up by 2* the last
interval
backoff_interval = backoff_interval * 2
# loop and try to restart the process
# log a service stopped message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ' (%s) ' % self._svc_display_name_))
class NullOutput:
"""A stdout / stderr replacement that discards everything."""
def noop(self, *args, **kw):
pass
write = writelines = close = seek = flush = truncate = noop
def __iter__(self):
return self
def next(self):
raise StopIteration
def isatty(self):
return False
def tell(self):
return 0
def read(self, *args, **kw):
return ''
readline = read
def readlines(self, *args, **kw):
return []
class MyFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title, wxDefaultPosition,
wxSize(200, 150))
self.CreateStatusBar()
self.SetStatusText("This is the statusbar")
menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this
program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wxMenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
# 서비스명
servicenameText = wxStaticText(self, -1, "Service Name")
self.servicenameCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 서비스로 ì‹¤í–‰í• ëª…ë ¹
cmdText = wxStaticText(self, -1, "Service command")
self.cmdCtrl = wxTextCtrl(self, -1, size=(200, -1))
# 실행 버튼
installButton = wxButton(self, -1, label="Install", size=(80,
-1))
removeButton = wxButton(self, -1, label="Remove", size=(80,
-1))
startButton = wxButton(self, -1, label="Start", size=(80, -1))
stopButton = wxButton(self, -1, label="Stop", size=(80, -1))
installButton.Bind(EVT_BUTTON, self.onInstallButtonClick)
removeButton.Bind(EVT_BUTTON, self.onRemoveButtonClick)
startButton.Bind(EVT_BUTTON, self.onStartButtonClick)
stopButton.Bind(EVT_BUTTON, self.onStopButtonClick)
# Sizer 구성
sizer = wxFlexGridSizer(rows=2, cols=2, hgap=10, vgap=5)
sizer.Add(servicenameText) # (0, 0)
sizer.Add(self.servicenameCtrl) # (0, 1)
sizer.Add(cmdText) # (1, 0)
sizer.Add(self.cmdCtrl) # (1, 1)
sizer.Add(installButton) # (2, 0)
sizer.Add(removeButton) # (2, 1)
sizer.Add(startButton) # (3, 0)
sizer.Add(stopButton) # (3, 1)
border = wxBoxSizer()
border.Add(sizer, 0, wxALL, 10)
self.SetSizerAndFit(border)
self.Fit()
def onInstallButtonClick(self, event):
Service.info[0] = self.servicenameCtrl.GetValue()
Service.info[1] = self.servicenameCtrl.GetValue()
Service.info[2] = self.cmdCtrl.GetValue()
#Service._svc_name_ = self.servicenameCtrl.GetValue()
#Service._svc_display_name_ = self.servicenameCtrl.GetValue()
#Service.start_cmd = self.cmdCtrl.GetValue()
#win32serviceutil.HandleCommandLine(Service)
win32serviceutil.InstallService(
win32serviceutil.GetServiceClassString(Service),
self.servicenameCtrl.GetValue(),
self.servicenameCtrl.GetValue()
)
def onRemoveButtonClick(self, event):
win32serviceutil.RemoveService(self.servicenameCtrl.GetValue())
def onStartButtonClick(self, event):
win32serviceutil.StartService(self.servicenameCtrl.GetValue())
def onStopButtonClick(self, event):
win32serviceutil.StopService(self.servicenameCtrl.GetValue())
#def onOkButtonClick(self, event):
# Service._svc_name_ = self.servicenameCtrl.GetValue()
# Service._svc_display_name_ = self.servicenameCtrl.GetValue()
# Service.start_cmd = (self.cmdCtrl.GetValue())
# sys.argv.append(self.argsCtrl.GetValue())
# win32serviceutil.HandleCommandLine(Service)
class MyApp(wxApp):
def OnInit(self):
frame = MyFrame(NULL, -1, "Hello from wxPython")
frame.servicenameCtrl.SetValue(r"moin_service")
frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")
#frame.argsCtrl.SetValue("stop")
Service.info[0] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[1] =
frame.servicenameCtrl.SetValue(r"moin_service")
Service.info[2] = frame.cmdCtrl.SetValue(r"c:\mmde\moin.exe")
frame.Show(true)
self.SetTopWindow(frame)
return true
if __name__ == '__main__':
app = MyApp(0)
app.MainLoop()