Mercurial > p > roundup > code
comparison roundup/scripts/roundup_server.py @ 2840:a212699c21f2
windows service part rewritten to take in account command line options;
require logfile for windows service;
log service startup and shutdown in windows event log
| author | Alexander Smishlajev <a1s@users.sourceforge.net> |
|---|---|
| date | Fri, 29 Oct 2004 20:39:31 +0000 |
| parents | 91b2d50f0b1a |
| children | 98e2e7b57101 |
comparison
equal
deleted
inserted
replaced
| 2839:f965de0c1e75 | 2840:a212699c21f2 |
|---|---|
| 15 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 15 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 16 # | 16 # |
| 17 | 17 |
| 18 """Command-line script that runs a server over roundup.cgi.client. | 18 """Command-line script that runs a server over roundup.cgi.client. |
| 19 | 19 |
| 20 $Id: roundup_server.py,v 1.68 2004-10-29 17:57:17 a1s Exp $ | 20 $Id: roundup_server.py,v 1.69 2004-10-29 20:39:31 a1s Exp $ |
| 21 """ | 21 """ |
| 22 __docformat__ = 'restructuredtext' | 22 __docformat__ = 'restructuredtext' |
| 23 | 23 |
| 24 import errno, cgi, getopt, os, socket, sys, traceback, urllib | 24 import errno, cgi, getopt, os, socket, sys, traceback, urllib |
| 25 import ConfigParser, BaseHTTPServer, SocketServer, StringIO | 25 import ConfigParser, BaseHTTPServer, SocketServer, StringIO |
| 426 import win32file | 426 import win32file |
| 427 | 427 |
| 428 class SvcShutdown(Exception): | 428 class SvcShutdown(Exception): |
| 429 pass | 429 pass |
| 430 | 430 |
| 431 class RoundupService(win32serviceutil.ServiceFramework, | 431 class RoundupService(win32serviceutil.ServiceFramework): |
| 432 BaseHTTPServer.HTTPServer): | 432 |
| 433 ''' A Roundup standalone server for Win32 by Ewout Prangsma | |
| 434 ''' | |
| 435 _svc_name_ = "Roundup Bug Tracker" | 433 _svc_name_ = "Roundup Bug Tracker" |
| 436 _svc_display_name_ = "Roundup Bug Tracker" | 434 _svc_display_name_ = "Roundup Bug Tracker" |
| 437 def __init__(self, args): | 435 |
| 438 # redirect stdout/stderr to our logfile | 436 running = 0 |
| 439 if LOGFILE: | 437 server = None |
| 440 # appending, unbuffered | 438 |
| 441 sys.stdout = sys.stderr = open(LOGFILE, 'a', 0) | 439 def SvcDoRun(self): |
| 442 win32serviceutil.ServiceFramework.__init__(self, args) | |
| 443 BaseHTTPServer.HTTPServer.__init__(self, self.address, | |
| 444 RoundupRequestHandler) | |
| 445 | |
| 446 # Create the necessary NT Event synchronization objects... | |
| 447 # hevSvcStop is signaled when the SCM sends us a notification | |
| 448 # to shutdown the service. | |
| 449 self.hevSvcStop = win32event.CreateEvent(None, 0, 0, None) | |
| 450 | |
| 451 # hevConn is signaled when we have a new incomming connection. | |
| 452 self.hevConn = win32event.CreateEvent(None, 0, 0, None) | |
| 453 | |
| 454 # Hang onto this module for other people to use for logging | |
| 455 # purposes. | |
| 456 import servicemanager | 440 import servicemanager |
| 457 self.servicemanager = servicemanager | 441 self.ReportServiceStatus(win32service.SERVICE_START_PENDING) |
| 442 config = ServerConfig() | |
| 443 (optlist, args) = config.getopt(sys.argv[1:]) | |
| 444 if not config["LOGFILE"]: | |
| 445 servicemanager.LogMsg(servicemanager.EVENTLOG_ERROR_TYPE, | |
| 446 servicemanager.PYS_SERVICE_STOPPED, | |
| 447 (self._svc_display_name_, "\r\nMissing logfile option")) | |
| 448 self.ReportServiceStatus(win32service.SERVICE_STOPPED) | |
| 449 return | |
| 450 self.server = config.get_server() | |
| 451 self.running = 1 | |
| 452 self.ReportServiceStatus(win32service.SERVICE_RUNNING) | |
| 453 servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, | |
| 454 servicemanager.PYS_SERVICE_STARTED, (self._svc_display_name_, | |
| 455 " at %s:%s" % (config["HOST"], config["PORT"]))) | |
| 456 while self.running: | |
| 457 self.server.handle_request() | |
| 458 servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, | |
| 459 servicemanager.PYS_SERVICE_STOPPED, | |
| 460 (self._svc_display_name_, "")) | |
| 461 self.ReportServiceStatus(win32service.SERVICE_STOPPED) | |
| 458 | 462 |
| 459 def SvcStop(self): | 463 def SvcStop(self): |
| 460 # Before we do anything, tell the SCM we are starting the | 464 self.running = 0 |
| 461 # stop process. | 465 # make dummy connection to self to terminate blocking accept() |
| 466 addr = self.server.socket.getsockname() | |
| 467 if addr[0] == "0.0.0.0": | |
| 468 addr = ("127.0.0.1", addr[1]) | |
| 469 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| 470 sock.connect(addr) | |
| 471 sock.close() | |
| 462 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) | 472 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) |
| 463 win32event.SetEvent(self.hevSvcStop) | |
| 464 | |
| 465 def SvcDoRun(self): | |
| 466 try: | |
| 467 self.serve_forever() | |
| 468 except SvcShutdown: | |
| 469 pass | |
| 470 | |
| 471 def get_request(self): | |
| 472 # Call WSAEventSelect to enable self.socket to be waited on. | |
| 473 win32file.WSAEventSelect(self.socket, self.hevConn, | |
| 474 win32file.FD_ACCEPT) | |
| 475 while 1: | |
| 476 try: | |
| 477 rv = self.socket.accept() | |
| 478 except socket.error, why: | |
| 479 if why[0] != win32file.WSAEWOULDBLOCK: | |
| 480 raise | |
| 481 # Use WaitForMultipleObjects instead of select() because | |
| 482 # on NT select() is only good for sockets, and not general | |
| 483 # NT synchronization objects. | |
| 484 rc = win32event.WaitForMultipleObjects( | |
| 485 (self.hevSvcStop, self.hevConn), | |
| 486 0, win32event.INFINITE) | |
| 487 if rc == win32event.WAIT_OBJECT_0: | |
| 488 # self.hevSvcStop was signaled, this means: | |
| 489 # Stop the service! | |
| 490 # So we throw the shutdown exception, which gets | |
| 491 # caught by self.SvcDoRun | |
| 492 raise SvcShutdown | |
| 493 # Otherwise, rc == win32event.WAIT_OBJECT_0 + 1 which means | |
| 494 # self.hevConn was signaled, which means when we call | |
| 495 # self.socket.accept(), we'll have our incoming connection | |
| 496 # socket! | |
| 497 # Loop back to the top, and let that accept do its thing... | |
| 498 else: | |
| 499 # yay! we have a connection | |
| 500 # However... the new socket is non-blocking, we need to | |
| 501 # set it back into blocking mode. (The socket that accept() | |
| 502 # returns has the same properties as the listening sockets, | |
| 503 # this includes any properties set by WSAAsyncSelect, or | |
| 504 # WSAEventSelect, and whether its a blocking socket or not.) | |
| 505 # | |
| 506 # So if you yank the following line, the setblocking() call | |
| 507 # will be useless. The socket will still be in non-blocking | |
| 508 # mode. | |
| 509 win32file.WSAEventSelect(rv[0], self.hevConn, 0) | |
| 510 rv[0].setblocking(1) | |
| 511 break | |
| 512 return rv | |
| 513 | 473 |
| 514 def usage(message=''): | 474 def usage(message=''): |
| 515 if RoundupService: | 475 if RoundupService: |
| 516 os_part = \ | 476 os_part = \ |
| 517 ""''' -c <Command> Windows Service options. | 477 ""''' -c <Command> Windows Service options. |
| 619 usage(str(e)) | 579 usage(str(e)) |
| 620 return | 580 return |
| 621 | 581 |
| 622 # if running in windows service mode, don't do any other stuff | 582 # if running in windows service mode, don't do any other stuff |
| 623 if ("-c", "") in optlist: | 583 if ("-c", "") in optlist: |
| 584 # acquire command line options recognized by service | |
| 585 short_options = "c:C:" | |
| 586 long_options = ["config"] | |
| 587 for (long_name, short_name) in config.OPTIONS.items(): | |
| 588 short_options += short_name | |
| 589 long_name = long_name.lower().replace("_", "-") | |
| 590 if short_name[-1] == ":": | |
| 591 long_name += "=" | |
| 592 long_options.append(long_name) | |
| 593 optlist = getopt.getopt(sys.argv[1:], short_options, long_options)[0] | |
| 594 svc_args = [] | |
| 595 for (opt, arg) in optlist: | |
| 596 if opt in ("-C", "-l"): | |
| 597 # make sure file name is absolute | |
| 598 svc_args.extend((opt, os.path.abspath(arg))) | |
| 599 elif opt in ("--config", "--logfile"): | |
| 600 # ditto, for long options | |
| 601 svc_args.append("=".join(opt, os.path.abspath(arg))) | |
| 602 elif opt != "-c": | |
| 603 svc_args.extend(opt) | |
| 604 RoundupService._exe_args_ = " ".join(svc_args) | |
| 605 # pass the control to serviceutil | |
| 624 win32serviceutil.HandleCommandLine(RoundupService, | 606 win32serviceutil.HandleCommandLine(RoundupService, |
| 625 argv=sys.argv[:1] + args) | 607 argv=sys.argv[:1] + args) |
| 626 return | 608 return |
| 627 | 609 |
| 628 # add tracker names from command line. | 610 # add tracker names from command line. |
