Python Cookbook by
Get full access to Python Cookbook and 60K+ other titles, with a free 10-day trial of O’Reilly.
There are also live events, courses curated by job role, and more.
Manipulating Windows Services
Problem
You need to control Windows services on any local machine.
Solution
The win32all package includes a win32serviceutil module that is specifically designed to handle Windows services:
# needs win32all, or ActiveState's ActivePython distribution import win32serviceutil def service_running(service, machine): return win32serviceutil.QueryServiceStatus(service, machine)[1] == 4 def service_info(action, machine, service): running = service_running(service, machine) servnam = 'service (%s) on machine(%s)'%(service, machine) action = action.lower( ) if action == 'stop': if not running: print "Can't stop, %s not running"%servnam return 0 win32serviceutil.StopService(service, machine) running = service_running(service, machine) if running: print "Can't stop %s (. )"%servnam return 0 print '%s stopped successfully' % servnam elif action == 'start': if running: print "Can't start, %s already running"%servnam return 0 win32serviceutil.StartService(service, machine) running = service_running(service, machine) if not running: print "Can't start %s (. )"%servnam return 0 print '%s started successfully' % servnam elif action == 'restart': if not running: print "Can't restart, %s not running"%servnam return 0 win32serviceutil.RestartService(service, machine) running = service_running(service, machine) if not running: print "Can't restart %s (. )"%servnam return 0 print '%s restarted successfully' % servnam elif action == 'status': if running: print "%s is running" % servnam else: print "%s is not running" % servnam else: print "Unknown action (%s) requested on %s"%(action, servnam) if _ _name_ _ == '_ _main_ _': # Just some test code; change at will! machine = 'cr582427-a' service = 'Zope23' action = 'start' service_info(action, machine, service)
Discussion
Mark Hammond’s win32all package makes it child’s play to code Python scripts for a huge variety of Windows system-administration tasks. For example, controlling Windows services becomes a snap. In addition to the few features exemplified in this recipe, which are similar to those provided by Windows’ own net command, win32all also gives you options such as installing and removing services.
The functions this recipe uses from the win32serviceutil module are StartService , StopService , RestartService , and QueryServiceStatus . Each takes two arguments: the name of the service and the name of the machine. The first three perform the start, stop, and restart as requested. The fourth returns a structured code describing whether and how the given service is running on the given machine, but in this recipe we exploit only the fact, encapsulated in the recipe’s service_running function, that the second item of the return value is the integer 4 if and only if the service is running successfully.
See Also
Documentation for win32serviceutil in win32all (http://starship.python.net/crew/mhammond/win32/Downloads.html) or ActivePython (http://www.activestate.com/ActivePython/); Windows API documentation available from Microsoft (http://msdn.microsoft.com); Python Programming on Win32 , by Mark Hammond and Andy Robinson (O’Reilly).
Get Python Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.
The winserviceutil Module Manage Windows Services
Windows services are processes that run on a Windows desktop or a Windows server machine. They can be remotely started, stopped, restarted, and queried for status. To manage Windows services, there is the win32serviceutil module, found in Mark Hammond’s win32all package.
For information on how to get the win32all package, please see Appendix B.
The following example shows how to start a service, stop a service, restart a service, or get service status through Python:
import win32serviceutil, time
def service_info(action, machine, service):
print ‘%s stopped successfully’ % service
print ‘%s started successfully’ % service
print ‘%s restarted successfully’ % service
if win32serviceutil.QueryServiceStatus(service, machine)[1] =
print «%s is running normally» % service
print «%s is *not* running» % service
service_info(‘start’, machine, service)
service_info(‘stop’, machine, service)
service_info(‘start’, machine, service)
service_info(‘restart’, machine, service)
service_info(‘status’, machine, service)
Because this example is a little longer than the others, let’s examine it section by section.
The service_info function takes an action, a machine, and a service name as parameters:
def service_info(action, machine, service):
The rest of the function is simply an if structure that performs actions on the service based on the action parameter passed in:
win32serviceutil.StopService(service, machine) print ‘%s stopped successfully’ % service time.sleep(3) elif action == ‘start’:
win32serviceutil.StartService(service, machine) print ‘%s started successfully’ % service time.sleep(3) elif action == ‘restart’:
win32serviceutil.RestartService(service, machine) print ‘%s restarted successfully’ % service time.sleep(3) elif action == ‘status’:
if win32serviceutil.QueryServiceStatus(service, machine)[1] == 4:
print «%s is running normally» % service else:
print «%s is *not* running» % service
This function could be accessed by another program by importing the module, but in this case we want to be able to run the program, so some code is added at the bottom of the program to run the function multiple times, with different parameters:
Using Python to Manage Windows Services
I recently ran into a little problem with a Windows service.
Apache Tomcat, about once every two weeks or so, simply croaks on one of our servers. When I say croaks, I mean croaks: a hit to :8080 gives a fast no-server-listening-whatsoever message.
Tomcat logs lead me to belive it’s a java memory issue, but as that service is moving to a new virtual server soon, I don’t want to get too deep in it yet in case it just goes away after the move (lazy > smart). That doesn’t mean I want to spend a lot of time periodically checking on it, however.
There are any number of great enterprise monitoring tools for this sort of thing, such as Nagios and Zenoss, which are for the most part free and open source. That would have been like squirrel hunting with a bazooka in this case, however, and both of the aforementioned products wouldn’t jive well with our Linux-phobic IT department. But a little Python can easily do the trick.
First you need to install the Python for Windows extension, which adds a lot of neat functions, including what we’re looking for — win32serviceutil. Now we build a simple function to stop, start, restart, or query the status of a Windows service.
def service_manager(action, machine, service): if action == 'stop': win32serviceutil.StopService(service, machine) elif action == 'start': win32serviceutil.StartService(service, machine) elif action == 'restart': win32serviceutil.RestartService(service, machine) elif action == 'status': if win32serviceutil.QueryServiceStatus(service, machine)[1] == 4: print "%s is happy" % service else: print "%s is being a PITA" % service
Now we’re off and running. Since the problem here is Tomcat just up and dies, a simple urlopen to Apache will do it.
import urllib import socket import win32serviceutil def service_info(action, machine, service): . socket.setdefaulttimeout(30) try: f = urllib.urlopen("http://servername:8080/") print "Tomcat is smokin'." except: print "Tomcat is dead. Restarting the service." service_manager("restart", "servername", "Apache Tomcat")
This little bit of code sets the default connection timeout to 30 seconds, so if the service is up and running, it will spend up to 30 seconds loading the URL to f. If that runs without error, we’re golden. If a socket error occurs (i.e. Tomcat is not talking), the exept block is executed, restarting the Tomcat service. Set the tiny script to run every 10 minutes or so, Bob’s your uncle, a self-healing server.
You can do quite a few service management tricks with this simple code. Say you’ve got an ArcIMS server that’s croaking on you (not an uncommon thing). Wouldn’t it be nice if the services would simply restart themselves?
Let’s say you have a map service named map_service on a server named servername (we’re also implying you’re incredibly uncreative here). ArcIMS is making images that look like so:
map_service_SERVERNAME24642500375.xxx
If ArcIMS has taken a walk, a hit to a web page with the map on it won’t have a link to your map image. So we hit the page, look for the “map_service_SERVERNAME” text string, and if it doesn’t find it, we restart the services:
f = urllib.urlopen("http://URL-to-page-with-map/") s = f.read() if s.find("map_service_SERVERNAME") == -1 : print "Restarting ArcIMS." service_manager("stop", "servername", "ArcIMS Tasker 9.x") service_manager("stop", "servername", "ArcIMS Monitor 9.x") service_manager("stop", "servername", "ArcIMS Application Server 9.x") service_manager("start", "servername", "ArcIMS Application Server 9.x") service_manager("start", "servername", "ArcIMS Monitor 9.x") service_manager("start", "servername", "ArcIMS Tasker 9.x") else: print "ArcIMS OK! Send ESRI a check!"
Viola — if ArcIMS is down, our script will spank it back to life while we’re spinning about in our chairs. The maximum down time will be service_death + time_to_next_script_run + arcims_comes_back_to_life_time, the latter of which can take a while. But the customer-calls-help-desk-calls-you-login-manually-restart process takes even longer, and there’s no telling how long it’s down before it gets to your desk.
Of course you can do quite a bit more with this stuff — send yourself an email or SMS message, log things to a file or the event log, etc. — but this should give you some ideas. Python is a great langauge for a lot of different server management tasks.
Tobin Bradley
A designer, developer and writer. Spends his time traveling the world with a bag of kites.