Package ClusterShell :: Package Worker :: Module Popen
[hide private]
[frames] | no frames]

Source Code for Module ClusterShell.Worker.Popen

  1  # 
  2  # Copyright CEA/DAM/DIF (2008, 2009, 2010) 
  3  #  Contributor: Stephane THIELL <stephane.thiell@cea.fr> 
  4  # 
  5  # This file is part of the ClusterShell library. 
  6  # 
  7  # This software is governed by the CeCILL-C license under French law and 
  8  # abiding by the rules of distribution of free software.  You can  use, 
  9  # modify and/ or redistribute the software under the terms of the CeCILL-C 
 10  # license as circulated by CEA, CNRS and INRIA at the following URL 
 11  # "http://www.cecill.info". 
 12  # 
 13  # As a counterpart to the access to the source code and  rights to copy, 
 14  # modify and redistribute granted by the license, users are provided only 
 15  # with a limited warranty  and the software's author,  the holder of the 
 16  # economic rights,  and the successive licensors  have only  limited 
 17  # liability. 
 18  # 
 19  # In this respect, the user's attention is drawn to the risks associated 
 20  # with loading,  using,  modifying and/or developing or reproducing the 
 21  # software by the user in light of its specific status of free software, 
 22  # that may mean  that it is complicated to manipulate,  and  that  also 
 23  # therefore means  that it is reserved for developers  and  experienced 
 24  # professionals having in-depth computer knowledge. Users are therefore 
 25  # encouraged to load and test the software's suitability as regards their 
 26  # requirements in conditions enabling the security of their systems and/or 
 27  # data to be ensured and,  more generally, to use and operate it in the 
 28  # same conditions as regards security. 
 29  # 
 30  # The fact that you are presently reading this means that you have had 
 31  # knowledge of the CeCILL-C license and that you accept its terms. 
 32  # 
 33  # $Id: Popen.py 292 2010-07-15 22:43:46Z st-cea $ 
 34   
 35  """ 
 36  WorkerPopen 
 37   
 38  ClusterShell worker for executing local commands. 
 39   
 40  Usage example: 
 41     >>> worker = WorkerPopen("/bin/uname", key="mykernel")  
 42     >>> task.schedule(worker)    # schedule worker 
 43     >>> task.resume()            # run task 
 44     >>> worker.retcode()         # get return code 
 45     0 
 46     >>> worker.read()            # read command output 
 47     'Linux' 
 48   
 49  """ 
 50   
 51  import os 
 52  import signal 
 53   
 54  from ClusterShell.Worker.Worker import WorkerSimple, WorkerBadArgumentError 
 55   
 56   
57 -class WorkerPopen(WorkerSimple):
58 """ 59 Implements the Popen Worker. 60 """ 61
62 - def __init__(self, command, key=None, handler=None, 63 stderr=False, timeout=-1, autoclose=False):
64 """ 65 Initialize Popen worker. 66 """ 67 WorkerSimple.__init__(self, None, None, None, key, handler, 68 stderr, timeout, autoclose) 69 70 self.command = command 71 if not self.command: 72 raise WorkerBadArgumentError() 73 74 self.popen = None 75 self.rc = None
76
77 - def _start(self):
78 """ 79 Start worker. 80 """ 81 assert self.popen is None 82 83 self.popen = self._exec_nonblock(self.command, shell=True) 84 self.file_reader = self.popen.stdout 85 self.file_error = self.popen.stderr 86 self.file_writer = self.popen.stdin 87 88 if self.task.info("debug", False): 89 self.task.info("print_debug")(self.task, "POPEN: %s" % self.command) 90 91 self._invoke("ev_start") 92 93 return self
94
95 - def _close(self, force, timeout):
96 """ 97 Close worker. Called by engine after worker has been 98 unregistered. This method should handle all termination types 99 (normal, forced or on timeout). 100 """ 101 if not force and self._rbuf: 102 # We still have some read data available in buffer, but no 103 # EOL. Generate a final message before closing. 104 self.worker._on_msgline(self._rbuf) 105 106 rc = -1 107 if force or timeout: 108 # check if process has terminated 109 prc = self.popen.poll() 110 if prc is None: 111 # process is still running, kill it 112 os.kill(self.popen.pid, signal.SIGKILL) 113 else: 114 # close process / check if it has terminated 115 prc = self.popen.wait() 116 # get exit status 117 if prc >= 0: 118 # process exited normally 119 rc = prc 120 else: 121 # if process was signaled, return 128 + signum (bash-like) 122 rc = 128 + -prc 123 124 self.popen.stdin.close() 125 self.popen.stdout.close() 126 127 if rc >= 0: 128 self._on_rc(rc) 129 elif timeout: 130 self._on_timeout() 131 132 self._invoke("ev_close")
133
134 - def _on_rc(self, rc):
135 """ 136 Set return code. 137 """ 138 self.rc = rc 139 self.task._rc_set((self, self.key), rc) 140 141 self._invoke("ev_hup")
142
143 - def retcode(self):
144 """ 145 Return return code or None if command is still in progress. 146 """ 147 return self.rc
148