Back to index

nagios-plugins  1.4.16
Public Member Functions | Public Attributes
utils.Task Class Reference

List of all members.

Public Member Functions

def __init__
def Run
def Wait
def Kill
def Done
def Status
def __str__

Public Attributes

 cmd
 words
 pid
 status

Detailed Description

Manage asynchronous subprocess tasks.
   This differs from the 'subproc' package!
    - 'subproc' connects to the subprocess via pipes
    - 'task' lets the subprocess run autonomously.
   After starting the task, we can just:
    - ask whether it is finished yet
    - wait until it is finished
    - perform an 'idle' task (e.g. Tkinter's mainloop) while waiting for
      subprocess termination
    - kill the subprocess with a specific signal
    - ask for the exit code.
   Summarizing:
    - 'subproc' is a sophisticated os.popen()
    - 'task' is a sophisticated os.system()
   Another difference of task with 'subproc':
    - If the Task() object is deleted, before the subprocess status
      was retrieved, the child process will stay.
      It will never be waited for (i.e., the process will turn into
      a zombie. Not a good idea in general).

   Public data:
       None.

   Public methods:
       __init__, __str__, Run, Wait, Kill, Done, Status.

Definition at line 44 of file utils.py.


Constructor & Destructor Documentation

def utils.Task.__init__ (   self,
  command 
)
Constructor.
   arguments:
       command: the command to run, in the form of a string,
        or a tuple or list of words.

Definition at line 71 of file utils.py.

00071 
00072     def __init__(self,command):
00073         """Constructor.
00074            arguments:
00075                command: the command to run, in the form of a string,
00076                         or a tuple or list of words.
00077            """
00078         if type(command)==type(''):
00079             self.cmd=command
00080             self.words=string.split(command)
00081         elif type(command)==type([]) or type(command)==type(()):
00082             # Surround each word by ' '. Limitation: words cannot contain ' chars
00083             self.cmd="'"+string.join(command,"' '")+"'"
00084             self.words=tuple(command)
00085         else:
00086             raise error("command must be tuple, list, or string")
00087         self.pid=None
00088         self.status=None


Member Function Documentation

def utils.Task.__str__ (   self)

Definition at line 251 of file utils.py.

00251 
00252     def __str__(self):
00253         if self.pid!=None:
00254             if self.status!=None:
00255                 s2="done, exit status=%d"%self.status
00256             else:
00257                 s2="running"
00258         else:
00259             s2="prepared"
00260         return "<%s: '%s', %s>"%(self.__class__.__name__,self.cmd,s2)
00261 
00262 
00263 #==========================================================================
00264 #
00265 #
00266 # Class: TimeoutHandler
00267 # License: GPL
00268 # Copyright (c)  2000 Jacob Lundqvist (jaclu@galdrion.com)
00269 #
00270 # Version: 1.0  2000-07-14
00271 #
00272 # Description:
00273 #  On init, suply a call-back kill_func that should be called on timeout
00274 #
00275 #  Make sure that what ever you are doing is calling Check periodically
00276 # 
00277 #  To check if timeout was triggered call WasTimeOut returns (true/false)
00278 #

def utils.Task.Done (   self)
Ask whether the process has already finished.
   return value:
       1: yes, the process has finished.
       0: no, the process has not finished yet.

Definition at line 224 of file utils.py.

00224 
00225     def Done(self):
00226         """Ask whether the process has already finished.
00227            return value:
00228                1: yes, the process has finished.
00229                0: no, the process has not finished yet.
00230         """
00231         if self.status!=None:
00232             return 1
00233         else:
00234             pid,status=os.waitpid(self.pid,os.WNOHANG)
00235             if pid==self.pid:
00236                 #print "OK:",pid,status
00237                 self.status=status
00238                 return 1
00239             else:
00240                 #print "NOK:",pid,status
00241                 return 0

Here is the caller graph for this function:

def utils.Task.Kill (   self,
  signal = signal.SIGTERM 
)
Send a signal to the running subprocess.
   optional arguments:
       signal=SIGTERM: number of the signal to send.
               (see os.kill)
   return value:
       see os.kill()

Definition at line 212 of file utils.py.

00212 
00213     def Kill(self,signal=signal.SIGTERM):
00214         """Send a signal to the running subprocess.
00215            optional arguments:
00216                signal=SIGTERM: number of the signal to send.
00217                                (see os.kill)
00218            return value:
00219                see os.kill()
00220         """
00221         if self.status==None:
00222             # Only if it is not already finished
00223             return os.kill(self.pid,signal)

Here is the caller graph for this function:

def utils.Task.Run (   self,
  usesh = 0,
  detach = 0,
  stdout = None,
  stdin = None,
  stderr = None 
)
Actually run the process.
   This method should be called exactly once.
   optional arguments:
       usesh=0: if 1, run 'sh -c command', if 0, split the
        command into words, and run it by ourselves.
        If usesh=1, the 'Kill' method might not do what
        you want (it will kill the 'sh' process, not the
        command).
       detach=0: if 1, run 'sh -c 'command&' (regardless of
         'usesh'). Since the 'sh' process will immediately
         terminate, the task created will be inherited by
         'init', so you can safely forget it.  Remember that if
         detach=1, Kill(), Done() and Status() will manipulate
         the 'sh' process; there is no way to find out about the
         detached process.
       stdout=None: filename to use as stdout for the child process.
            If None, the stdout of the parent will be used.
       stdin= None: filename to use as stdin for the child process.
            If None, the stdin of the parent will be used.
       stderr=None: filename to use as stderr for the child process.
            If None, the stderr of the parent will be used.
   return value:                            
       None

Definition at line 89 of file utils.py.

00089 
00090     def Run(self,usesh=0,detach=0,stdout=None,stdin=None,stderr=None):
00091         """Actually run the process.
00092            This method should be called exactly once.
00093            optional arguments:
00094                usesh=0: if 1, run 'sh -c command', if 0, split the
00095                         command into words, and run it by ourselves.
00096                         If usesh=1, the 'Kill' method might not do what
00097                         you want (it will kill the 'sh' process, not the
00098                         command).
00099                detach=0: if 1, run 'sh -c 'command&' (regardless of
00100                          'usesh'). Since the 'sh' process will immediately
00101                          terminate, the task created will be inherited by
00102                          'init', so you can safely forget it.  Remember that if
00103                          detach=1, Kill(), Done() and Status() will manipulate
00104                          the 'sh' process; there is no way to find out about the
00105                          detached process.
00106                stdout=None: filename to use as stdout for the child process.
00107                             If None, the stdout of the parent will be used.
00108                stdin= None: filename to use as stdin for the child process.
00109                             If None, the stdin of the parent will be used.
00110                stderr=None: filename to use as stderr for the child process.
00111                             If None, the stderr of the parent will be used.
00112            return value:                            
00113                None
00114         """
00115         if self.pid!=None:
00116             raise error("Second run on task forbidden")
00117         self.pid=os.fork()
00118         if not self.pid:
00119             for fn in range(3,256): # Close all non-standard files in a safe way
00120                 try:
00121                     os.close(fn)
00122                 except os.error:
00123                     pass
00124            #
00125            # jaclu@galdrion.com 2000-07-14
00126            #
00127            # I changed this bit somewhat, since Nagios plugins
00128            # should send only limited errors to the caller
00129            # The original setup here corupted output when there was an error.
00130            # Instead the caller should check result of Wait() and anything
00131            # not zero should be reported as a failure.
00132            #
00133            try:
00134               if stdout: # Replace stdout by file
00135                   os.close(1)
00136                   i=os.open(stdout,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
00137                   if i!=1:
00138                      sys.stderr.write("stdout not opened on 1!\n")
00139               if stdin: # Replace stdin by file
00140                   os.close(0)
00141                   i=os.open(stdin,os.O_RDONLY)
00142                   if i!=0:
00143                      sys.stderr.write("stdin not opened on 0!\n")
00144               if stderr: # Replace stderr by file
00145                   os.close(2)
00146                   i=os.open(stderr,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
00147                   if i!=2:
00148                      sys.stdout.write("stderr not opened on 2!\n")
00149               #try:
00150                 if detach:
00151                     os.execv('/bin/sh',('sh','-c',self.cmd+'&'))
00152                 elif usesh:
00153                     os.execv('/bin/sh',('sh','-c',self.cmd))
00154                 else:
00155                     os.execvp(self.words[0],self.words)
00156             except:
00157                 #print self.words
00158                 #sys.stderr.write("Subprocess '%s' execution failed!\n"%self.cmd)
00159                 sys.exit(1)
00160         else:
00161             # Mother process
00162             if detach:
00163                 # Should complete "immediately"
00164                 self.Wait()

Here is the call graph for this function:

def utils.Task.Status (   self)
Ask for the status of the task.
   return value:
       None: process has not finished yet (maybe not even started).
       any integer: process exit status.

Definition at line 242 of file utils.py.

00242 
00243     def Status(self):
00244         """Ask for the status of the task.
00245            return value:
00246                None: process has not finished yet (maybe not even started).
00247                any integer: process exit status.
00248         """
00249         self.Done()
00250         return self.status

Here is the call graph for this function:

def utils.Task.Wait (   self,
  idlefunc = None,
  interval = 0.1 
)
Wait for the subprocess to terminate.
   If the process has already terminated, this function will return
   immediately without raising an error.
   optional arguments:
       idlefunc=None: a callable object (function, class, bound method)
              that will be called every 0.1 second (or see
              the 'interval' variable) while waiting for
              the subprocess to terminate. This can be the
              Tkinter 'update' procedure, such that the GUI
              doesn't die during the run. If this is set to
              'None', the process will really wait. idlefunc
              should ideally not take a very long time to
              complete...
       interval=0.1: The interval (in seconds) with which the 'idlefunc'
             (if any) will be called.
   return value:
       the exit status of the subprocess (0 if successful).

Definition at line 165 of file utils.py.

00165 
00166     def Wait(self,idlefunc=None,interval=0.1):
00167         """Wait for the subprocess to terminate.
00168            If the process has already terminated, this function will return
00169            immediately without raising an error.
00170            optional arguments:
00171                idlefunc=None: a callable object (function, class, bound method)
00172                               that will be called every 0.1 second (or see
00173                               the 'interval' variable) while waiting for
00174                               the subprocess to terminate. This can be the
00175                               Tkinter 'update' procedure, such that the GUI
00176                               doesn't die during the run. If this is set to
00177                               'None', the process will really wait. idlefunc
00178                               should ideally not take a very long time to
00179                               complete...
00180                interval=0.1: The interval (in seconds) with which the 'idlefunc'
00181                              (if any) will be called.
00182            return value:
00183                the exit status of the subprocess (0 if successful).
00184         """
00185         if self.status!=None:
00186             # Already finished
00187             return self.status
00188         if callable(idlefunc):
00189             while 1:
00190                 try:
00191                     pid,status=os.waitpid(self.pid,os.WNOHANG)
00192                     if pid==self.pid:
00193                         self.status=status
00194                         return status
00195                     else:
00196                         idlefunc()
00197                         time.sleep(interval)
00198                 except KeyboardInterrupt:
00199                     # Send the interrupt to the inferior process.
00200                     self.Kill(signal=signal.SIGINT)
00201         elif idlefunc:
00202             raise error("Non-callable idle function")
00203         else:
00204             while 1:
00205                 try:
00206                     pid,status=os.waitpid(self.pid,0)
00207                     self.status=status
00208                     return status
00209                 except KeyboardInterrupt:
00210                     # Send the interrupt to the inferior process.
00211                     self.Kill(signal=signal.SIGINT)

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 78 of file utils.py.

Definition at line 86 of file utils.py.

Definition at line 87 of file utils.py.

Definition at line 79 of file utils.py.


The documentation for this class was generated from the following file: