Stuck on a simple open in python

software development

#1

I am trying to write a little python script to send me an email when a service has stopped on a windows server (not a dreamhost server). I’ve done stuff like this in perl, but I thought I should do this in python because the server already has python 2.5 installed and I need to learn more python.

I found the WService Class http://code.activestate.com/recipes/115875-controlling-windows-services/ right away and it worked great. In just a few lines. I could write something that would stay running until a service stopped, then I can branch to sending the email:

from sys import exit
import time, win32api, win32con, win32service
wa, wc, ws = win32api, win32con, win32service

import WService
iis = WService.WService(“IIS Admin”)
iis.fetchstatus(“stopped”)
print “IIS Stopped”

class WService:
**
**

but the email part has given me some problems, making me realize I don’t know much about python basics.

I’ve been trying to test with the simple text message example found around the net: http://docs.python.org/library/email-examples.html

Import smtplib for the actual sending function

import smtplib

Import the email modules we’ll need

from email.mime.text import MIMEText

Open a plain text file for reading. For this example, assume that

the text file contains only ASCII characters.

fp = open(‘textfile.txt’, ‘rb’)

Create a text/plain message

msg = MIMEText(fp.read())
fp.close()

me == "@yakama.com"
you == "
@yakama.com"
msg[‘Subject’] = ‘The contents of %s’ % 'textfile.txt’
msg[‘From’] = me
msg[‘To’] = you

Send the message via our own SMTP server, but don’t include the

envelope header.

s = smtplib.SMTP()
s.connect()
s.sendmail(me, [you], msg.as_string())
s.close()

But had some trouble figuring out where all my substitutions would go and what the syntax is supposed to be, like in quotes or not. But now I’m hitting an error at line 9: [quote]fp = open(‘textfile.txt’, ‘rb’)
IOError: [Errno 2] No such file or directory: ‘textfile.txt’[/quote] even though I created a textfile.txt in the same directory as the script. Why can’t I get open to work? Do I need to set a path?

I looked at the Google App Engine python email but apparently it didn’t install for me correctly. After running the msi, [quote]from google.appengine.api import mail[/quote] in an interactive window can’t find the module.


#2

I figured out a way to see what python’s default path to the text file is. In interactive window, I opened a new file named mailbody.txt with ‘w’, the write mode, and dropped a line of text into it. The searched C: for mailbody.txt. Found it in c:\python25. Now I’m using mailbody.txt for the msg. Couldn’t figure out how to add a path to the open statement.

Now I’m getting errors returned by line 22 or 23 when it tries to connect to a mail server. ‘Connection refused’, although one time trying mail.charter.net as the STMP server, I got a message that it didn’t permit connections from outside charter.nets IP. Trying many combinations of email addresses and mail hosts, but haven’t hit on the correct combination.


#3

This code worked for me, using gmail as my smtp server. But only when I tried running it from my Dreamhost server. Running from my PC, I just get “SMTP AUTH extension not supported by server”. Must have issues with the enterprise firewall at my location.


#4

Well, that was a good theory for a short time. It’s not a firewall problem because I get the same error [quote]File “C:\Python25\lib\smtplib.py”, line 554, in login
raise SMTPException(“SMTP AUTH extension not supported by server.”)
SMTPException: SMTP AUTH extension not supported by server. [/quote]
from windows xp locally and windows server at the other location. The script runs fine and sends mail from Linux both here at my office and my web server. What is it about windows that blocks mail authentication by default?


#5

I don’t understand why but adding a second server.ehlo() after server.starttls() seems to be necessary on windows machines. Gmail seems to be the only mail server that will play this way. Saw the tip about the second server.ehlo() at http://stackoverflow.com/questions/3…/399240#399240, the one posted by Jataro.

This is what is working for me now on windows:

[quote]import smtplib

FROMADDR = "******@gmail.com"
LOGIN = FROMADDR
PASSWORD = “******“
TOADDRS = [”******@yakama.com”]
SUBJECT = “Test from Paule6500 WindowXP”

msg = (“From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n”
% (FROMADDR, ", ".join(TOADDRS), SUBJECT) )
msg += “some text from windows xp at Nelson Springs\r\n”

server = smtplib.SMTP(‘smtp.gmail.com’, 587)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.ehlo()
server.login(LOGIN, PASSWORD)
server.sendmail(FROMADDR, TOADDRS, msg)
server.quit()[/quote]
I wonder if I can send to multiple email addresses.

The next step is to branch to this section when the service is found to be stopped by the section that uses the WService class.


#6

Well, it’s not elegant but this is what I’m going with. Seems to work. Not elegant in that I didn’t set up any parameters to input the service name and the email addresses, you have to edit them in. Not elegant in that there is no branching. No looping back at intervals to keep checking the service. It just starts, then hangs at the fetchstatus line. If the status of the service ever changes to “stopped”, then the script continues to the next lines and sends a email. It will tie up pythonwin running this way, but you can also run it from a command line. Taskmanager will show it as it hangs, and doesn’t seem to use any CPU. I suppose there is a way in windows to start it up during system startup. I’ll be able to try it on my troublesome ArcService system next week.

[quote]## ServiceAlert.py

Uses WService class, hangs at fetchstatus until it finds that the

IIS service is stopped, then continues to send emails to

two addresses to alert admins that there is a problem.

“”“
Module for manipulating WinNT, Win2k & WinXP services.
Requires the win32all package which can be retrieved
from => http://starship.python.net/crew/mhammond
”""
from sys import exit
import time, win32api, win32con, win32service
wa, wc, ws = win32api, win32con, win32service

import WService
#edit here to check the appropriate service. I used IIS Admin for testing
iis = WService.WService(“IIS Admin”)
iis.fetchstatus(“stopped”)
print “IIS Stopped”

import smtplib

#Edit here to insert your from and to email addresses, and from gmail password
FROMADDR = “******@gmail.com"
LOGIN = FROMADDR
PASSWORD = “******“
TOADDRS = [”******@yakama.com”]
TOADDRS2 = [”******@charter.net"]
#Edit here to insert a email that will fit your situataion
SUBJECT = “Test from Paule6500 WindowXP, Service stopped.”

msg = (“From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n”
% (FROMADDR, ", ".join(TOADDRS), SUBJECT) )
#edit the line below to customize the email content
msg += “IIS service on Paule6500 stopped. Needs some intervention.\r\n”

server = smtplib.SMTP(‘smtp.gmail.com’, 587)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.ehlo()
server.login(LOGIN, PASSWORD)
server.sendmail(FROMADDR, TOADDRS, msg)
server.sendmail(FROMADDR, TOADDRS2, msg)
server.quit()

class WService:
"""
The WService Class is used for controlling WinNT, Win2k & WinXP like
services. Just pass the name of the service you wish to control to the
class instance and go from there. For example, if you want to control
the Workstation service try this:

    import WService
    workstation = WService.WService("Workstation")
    workstation.start()
    workstation.fetchstatus("running", 10)
    workstation.stop()
    workstation.fetchstatus("stopped")

Creating an instance of the WService class is done by passing the name of
the service as it appears in the Management Console or the short name as
it appears in the registry. Mixed case is ok.
    cvs = WService.WService("CVS NT Service 1.11.1.2 (Build 41)")        
        or
    cvs = WService.WService("cvs")

If needing remote service control try this:
    cvs = WService.WService("cvs", r"\\CVS_SERVER")
        or
    cvs = WService.WService("cvs", "\\\\CVS_SERVER")  
    
The WService Class supports these methods:
    
    start:          Starts service.
    stop:           Stops service.
    restart:        Stops and restarts service.
    pause:          Pauses service (Only if service supports feature).
    resume:         Resumes service that has been paused.
    status:         Queries current status of service.
    fetchstatus:    Continually queries service until requested status(STARTING, RUNNING,
                        STOPPING & STOPPED) is met or timeout value(in seconds) reached.
                        Default timeout value is infinite.                              
    infotype:       Queries service for process type. (Single, shared and/or 
                        interactive process)
    infoctrl:       Queries control information about a running service.
                        i.e. Can it be paused, stopped, etc?
    infostartup:    Queries service Startup type. (Boot, System, 
                        Automatic, Manual, Disabled)
    setstartup      Changes/sets Startup type. (Boot, System, 
                        Automatic, Manual, Disabled)                    
    getname:        Gets the long and short service names used by Windows.
                        (Generally used for internal purposes)
"""    
    
def __init__(self, service, machinename=None, dbname=None):
    self.userv = service
    self.scmhandle = ws.OpenSCManager(machinename, dbname, ws.SC_MANAGER_ALL_ACCESS)
    self.sserv, self.lserv = self.getname()
    if (self.sserv or self.lserv) == None: exit()
    self.handle = ws.OpenService(self.scmhandle, self.sserv, ws.SERVICE_ALL_ACCESS)
    self.sccss = "SYSTEM\\CurrentControlSet\\Services\\"
    
def start(self):
    ws.StartService(self.handle, None)
    
def stop(self):
    self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_STOP)

def restart(self):
    self.stop()
    self.fetchstate("STOPPED")
    self.start()
    
def pause(self):
    self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_PAUSE)

def resume(self):
    self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_CONTINUE)
    
def status(self, prn = 0):
    self.stat = ws.QueryServiceStatus(self.handle)
    if self.stat[1]==ws.SERVICE_STOPPED:
        if prn == 1:
            print "The", self.lserv, "service is stopped."
        else:
            return "STOPPED"
    elif self.stat[1]==ws.SERVICE_START_PENDING:
        if prn == 1:
            print "The", self.lserv, "service is starting."
        else:
            return "STARTING"
    elif self.stat[1]==ws.SERVICE_STOP_PENDING:
        if prn == 1:
            print "The", self.lserv, "service is stopping."        
        else:
            return "STOPPING"
    elif self.stat[1]==ws.SERVICE_RUNNING:
        if prn == 1:
            print "The", self.lserv, "service is running."        
        else:
            return "RUNNING"
            
def fetchstatus(self, fstatus, timeout=None):
    self.fstatus = fstatus.upper()
    if timeout != None:
        timeout = int(timeout); timeout *= 2
    def to(timeout):
        time.sleep(.5)
        if timeout != None:
            if timeout > 1:
                timeout -= 1; return timeout
            else:
                return "TO"   
    if self.fstatus == "STOPPED":
        while 1:
            self.stat = ws.QueryServiceStatus(self.handle)
            if self.stat[1]==ws.SERVICE_STOPPED:
                self.fstate = "STOPPED"; break
            else:
                timeout=to(timeout)
                if timeout == "TO":
                    return "TIMEDOUT"; break
    elif self.fstatus == "STOPPING":
        while 1:
            self.stat = ws.QueryServiceStatus(self.handle)
            if self.stat[1]==ws.SERVICE_STOP_PENDING:
                self.fstate = "STOPPING"; break
            else:
                timeout=to(timeout)
                if timeout == "TO":
                    return "TIMEDOUT"; break                      
    elif self.fstatus == "RUNNING":
        while 1:
            self.stat = ws.QueryServiceStatus(self.handle)
            if self.stat[1]==ws.SERVICE_RUNNING:
                self.fstate = "RUNNING"; break
            else:
                timeout=to(timeout)
                if timeout == "TO":
                    return "TIMEDOUT"; break                       
    elif self.fstatus == "STARTING":
        while 1:
            self.stat = ws.QueryServiceStatus(self.handle)
            if self.stat[1]==ws.SERVICE_START_PENDING:
                self.fstate = "STARTING"; break
            else:
                timeout=to(timeout)
                if timeout == "TO":
                    return "TIMEDOUT"; break
    
def infotype(self):
    self.stat = ws.QueryServiceStatus(self.handle)
    if self.stat[0] & ws.SERVICE_WIN32_OWN_PROCESS:
        print "The", self.lserv, "service runs in its own process."
    if self.stat[0] & ws.SERVICE_WIN32_SHARE_PROCESS:
        print "The", self.lserv, "service shares a process with other services."
    if self.stat[0] & ws.SERVICE_INTERACTIVE_PROCESS:
        print "The", self.lserv, "service can interact with the desktop."
    
def infoctrl(self):
    self.stat = ws.QueryServiceStatus(self.handle)
    if self.stat[2] & ws.SERVICE_ACCEPT_PAUSE_CONTINUE:
        print "The", self.lserv, "service can be paused."
    if self.stat[2] & ws.SERVICE_ACCEPT_STOP:
        print "The", self.lserv, "service can be stopped."
    if self.stat[2] & ws.SERVICE_ACCEPT_SHUTDOWN:
        print "The", self.lserv, "service can be shutdown."    

def infostartup(self):
    self.isuphandle = wa.RegOpenKeyEx(wc.HKEY_LOCAL_MACHINE, self.sccss + self.sserv, 0, wc.KEY_READ)
    self.isuptype = wa.RegQueryValueEx(self.isuphandle, "Start")[0]
    wa.RegCloseKey(self.isuphandle)
    if self.isuptype == 0:
        return "boot"
    elif self.isuptype == 1:
        return "system"
    elif self.isuptype == 2:
        return "automatic"
    elif self.isuptype == 3:
        return "manual"
    elif self.isuptype == 4:
        return "disabled"
     
def setstartup(self, startuptype):
    self.startuptype = startuptype.lower()
    if self.startuptype == "boot":
        self.suptype = 0
    elif self.startuptype == "system":
        self.suptype = 1
    elif self.startuptype == "automatic":
        self.suptype = 2
    elif self.startuptype == "manual":
        self.suptype = 3
    elif self.startuptype == "disabled":
        self.suptype = 4
    self.snc = ws.SERVICE_NO_CHANGE
    ws.ChangeServiceConfig(self.handle, self.snc, self.suptype, \
    self.snc, None, None, 0, None, None, None, self.lserv) 
    
def getname(self):
    self.snames=ws.EnumServicesStatus(self.scmhandle)
    for i in self.snames:
        if i[0].lower() == self.userv.lower():
            return i[0], i[1]; break
        if i[1].lower() == self.userv.lower():
            return i[0], i[1]; break
    print "Error: The", self.userv, "service doesn't seem to exist."
    return None, None

end of http://code.activestate.com/recipes/115875/ }}}

[/quote]