nothing wrong with a stderr being not empty
[nepi.git] / nepi / resources / linux / application.py
index 94bd5e9..e4086b8 100644 (file)
 #
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
+import os
+import subprocess
+import logging
+
 from nepi.execution.attribute import Attribute, Flags, Types
 from nepi.execution.trace import Trace, TraceAttr
 from nepi.execution.resource import ResourceManager, clsinit_copy, \
         ResourceState
 from nepi.resources.linux.node import LinuxNode
-from nepi.util.sshfuncs import ProcStatus
+from nepi.util.sshfuncs import ProcStatus, STDOUT
 from nepi.util.timefuncs import tnow, tdiffsec
 
-import os
-import subprocess
+# to debug, just use
+# logging.getLogger('application').setLevel(logging.DEBUG)
+logger = logging.getLogger("application")
 
 # TODO: Resolve wildcards in commands!!
 # TODO: When a failure occurs during deployment, scp and ssh processes are left running behind!!
@@ -161,14 +166,17 @@ class LinuxApplication(ResourceManager):
             Attribute("tearDown",
                       "Command to be executed just before releasing the resource", 
                       flags = Flags.Design))
+        cls._register_attribute(
+            Attribute("splitStderr", 
+                      "requests stderr to be retrieved separately",
+                      default = False))
 
     @classmethod
     def _register_traces(cls):
-        stdout = Trace("stdout", "Standard output stream", enabled = True)
-        stderr = Trace("stderr", "Standard error stream", enabled = True)
-
-        cls._register_trace(stdout)
-        cls._register_trace(stderr)
+        cls._register_trace(
+            Trace("stdout", "Standard output stream", enabled = True))
+        cls._register_trace(
+            Trace("stderr", "Standard error stream", enabled = True))
 
     def __init__(self, ec, guid):
         super(LinuxApplication, self).__init__(ec, guid)
@@ -245,6 +253,7 @@ class LinuxApplication(ResourceManager):
         self.info("Retrieving '{}' trace {} ".format(name, attr))
 
         path = self.trace_filepath(name)
+        logger.debug("trace: path= {}".format(path))
         
         command = "(test -f {} && echo 'success') || echo 'error'".format(path)
         (out, err), proc = self.node.execute(command)
@@ -383,13 +392,20 @@ class LinuxApplication(ResourceManager):
             # in background ( but wait until the command has
             # finished to continue )
             shfile = os.path.join(self.app_home, "{}.sh".format(prefix))
+            # low-level spawn tools in both sshfuncs and execfuncs
+            # expect stderr=sshfuncs.STDOUT to mean std{out,err} are merged
+            stderr = "{}_stderr".format(prefix) \
+                     if self.get("splitStderr") \
+                        else STDOUT
+            print("{} : prefix = {}, command={}, stderr={}"
+                  .format(self, prefix, command, stderr))
             self.node.run_and_wait(command, self.run_home,
                                    shfile = shfile, 
                                    overwrite = False,
                                    pidfile = "{}_pidfile".format(prefix), 
                                    ecodefile = "{}_exitcode".format(prefix), 
                                    stdout = "{}_stdout".format(prefix),
-                                   stderr = "{}_stderr".format(prefix))
+                                   stderr = stderr)
 
     def upload_sources(self, sources = None, src_dir = None):
         if not sources:
@@ -583,7 +599,11 @@ class LinuxApplication(ResourceManager):
         sudo = self.get("sudo") or False
 
         stdout = "stdout"
-        stderr = "stderr"
+        # low-level spawn tools in both sshfuncs and execfuncs
+        # expect stderr=sshfuncs.STDOUT to mean std{out,err} are merged
+        stderr = "stderr" \
+                 if self.get("splitStderr") \
+                    else STDOUT
         stdin = os.path.join(self.app_home, "stdin") if self.get("stdin") \
                 else None
 
@@ -709,10 +729,15 @@ class LinuxApplication(ResourceManager):
                                 = self.node.check_errors(self.run_home)
 
                             if err:
-                                msg = "Failed to execute command '{}'"\
-                                      .format(self.get("command"))
-                                self.error(msg, out, err)
-                                self.do_fail()
+                                # Thierry : there's nothing wrong with a non-empty
+                                # stderr, is there ?
+                                #msg = "Failed to execute command '{}'"\
+                                #      .format(self.get("command"))
+                                #self.error(msg, out, err)
+                                #self.do_fail()
+                                # xxx TODO  OTOH it would definitely make sense
+                                # to check the exitcode
+                                pass
                             else:
                                 self.set_stopped()