+
+ def exitcode(self, home, ecodefile = "exitcode"):
+ """
+ Get the exit code of an application.
+ Returns an integer value with the exit code
+ """
+ (out, err), proc = self.check_output(home, ecodefile)
+
+ # Succeeded to open file, return exit code in the file
+ if proc.wait() == 0:
+ try:
+ return int(out.strip())
+ except:
+ # Error in the content of the file!
+ return ExitCode.CORRUPTFILE
+
+ # No such file or directory
+ if proc.returncode == 1:
+ return ExitCode.FILENOTFOUND
+
+ # Other error from 'cat'
+ return ExitCode.ERROR
+
+ def upload_command(self, command, home,
+ shfile = "cmd.sh",
+ ecodefile = "exitcode",
+ env = None):
+ """ Saves the command as a bash script file in the remote host, and
+ forces to save the exit code of the command execution to the ecodefile
+ """
+
+ if not (command.strip().endswith(";") or command.strip().endswith("&")):
+ command += ";"
+
+ # The exit code of the command will be stored in ecodefile
+ command = " { %(command)s } ; echo $? > %(ecodefile)s ;" % {
+ 'command': command,
+ 'ecodefile': ecodefile,
+ }
+
+ # Export environment
+ environ = self.format_environment(env)
+
+ # Add environ to command
+ command = environ + command
+
+ dst = os.path.join(home, shfile)
+ return self.upload(command, dst, text = True)
+
+ def format_environment(self, env, inline = False):
+ """Format environmental variables for command to be executed either
+ as an inline command
+ (i.e. export PYTHONPATH=src/..; export LALAL= ..;python script.py) or
+ as a bash script (i.e. export PYTHONPATH=src/.. \n export LALA=.. \n)
+ """
+ if not env: return ""
+ env = env.strip()
+
+ sep = ";" if inline else "\n"
+ return sep.join(map(lambda e: " export %s" % e, env.split(" "))) + sep
+
+ def check_errors(self, home,
+ ecodefile = "exitcode",
+ stdout = "stdout",
+ stderr = "stderr"):
+ """
+ Checks whether errors occurred while running a command.
+ It first checks the exit code for the command, and only if the
+ exit code is an error one it returns the error output.
+
+ """
+ proc = None
+ err = ""
+ # retrive standard output from the file
+ (out, oerr), oproc = self.check_output(home, stdout)
+
+ # get exit code saved in the 'exitcode' file
+ ecode = self.exitcode(home, ecodefile)
+
+ if ecode in [ ExitCode.CORRUPTFILE, ExitCode.ERROR ]:
+ err = "Error retrieving exit code status from file %s/%s" % (home, ecodefile)
+ elif ecode > 0 or ecode == ExitCode.FILENOTFOUND:
+ # The process returned an error code or didn't exist.
+ # Check standard error.
+ (err, eerr), proc = self.check_output(home, stderr)
+
+ # If the stderr file was not found, assume nothing bad happened,
+ # and just ignore the error.
+ # (cat returns 1 for error "No such file or directory")
+ if ecode == ExitCode.FILENOTFOUND and proc.poll() == 1:
+ err = ""
+
+ return (out, err), proc