Progress with LinuxTAP and UDP connections
[nepi.git] / src / nepi / resources / linux / application.py
index a1a9f97..08ea700 100644 (file)
@@ -63,14 +63,14 @@ class LinuxApplication(ResourceManager):
         The directory structure used by LinuxApplication RM at the Linux
         host is the following:
 
-        ${HOME}/nepi-usr --> Base directory for multi-experiment files
+        ${HOME}/.nepi/nepi-usr --> Base directory for multi-experiment files
                       |
         ${LIB}        |- /lib --> Base directory for libraries
         ${BIN}        |- /bin --> Base directory for binary files
         ${SRC}        |- /src --> Base directory for sources
         ${SHARE}      |- /share --> Base directory for other files
 
-        ${HOME}/nepi-exp --> Base directory for single-experiment files
+        ${HOME}/.nepi/nepi-exp --> Base directory for single-experiment files
                       |
         ${EXP_HOME}   |- /<exp-id>  --> Base directory for experiment exp-id
                           |
@@ -101,25 +101,25 @@ class LinuxApplication(ResourceManager):
                 "Space-separated list of packages required to run the application",
                 flags = Flags.Design)
         sources = Attribute("sources", 
-                "Space-separated list of regular files to be uploaded to ${SRC} "
+                "semi-colon separated list of regular files to be uploaded to ${SRC} "
                 "directory prior to building. Archives won't be expanded automatically. "
                 "Sources are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all sources). ",
                 flags = Flags.Design)
         files = Attribute("files", 
-                "Space-separated list of regular miscellaneous files to be uploaded "
+                "semi-colon separated list of regular miscellaneous files to be uploaded "
                 "to ${SHARE} directory. "
                 "Files are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
                 flags = Flags.Design)
         libs = Attribute("libs", 
-                "Space-separated list of libraries (e.g. .so files) to be uploaded "
+                "semi-colon separated list of libraries (e.g. .so files) to be uploaded "
                 "to ${LIB} directory. "
                 "Libraries are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
                 flags = Flags.Design)
         bins = Attribute("bins", 
-                "Space-separated list of binary files to be uploaded "
+                "semi-colon separated list of binary files to be uploaded "
                 "to ${BIN} directory. "
                 "Binaries are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
@@ -187,7 +187,7 @@ class LinuxApplication(ResourceManager):
 
         # timestamp of last state check of the application
         self._last_state_check = tnow()
-
+        
     def log_message(self, msg):
         return " guid %d - host %s - %s " % (self.guid, 
                 self.node.get("hostname"), msg)
@@ -274,6 +274,20 @@ class LinuxApplication(ResourceManager):
         return out
 
     def do_provision(self):
+        # take a snapshot of the system if user is root
+        # to ensure that cleanProcess will not kill
+        # pre-existent processes
+        if self.node.get("username") == 'root':
+            import pickle
+            procs = dict()
+            ps_aux = "ps aux |awk '{print $2,$11}'"
+            (out, err), proc = self.node.execute(ps_aux)
+            if len(out) != 0:
+                for line in out.strip().split("\n"):
+                    parts = line.strip().split(" ")
+                    procs[parts[0]] = parts[1]
+                pickle.dump(procs, open("/tmp/save.proc", "wb"))
+            
         # create run dir for application
         self.node.mkdir(self.run_home)
    
@@ -344,22 +358,30 @@ class LinuxApplication(ResourceManager):
                     env = env,
                     overwrite = overwrite)
 
-    def execute_deploy_command(self, command):
+    def execute_deploy_command(self, command, prefix="deploy"):
         if command:
+            # replace application specific paths in the command
+            command = self.replace_paths(command)
+            
+            # replace application specific paths in the environment
+            env = self.get("env")
+            env = env and self.replace_paths(env)
+
             # Upload the command to a bash script and run it
             # in background ( but wait until the command has
             # finished to continue )
-            shfile = os.path.join(self.app_home, "deploy.sh")
+            shfile = os.path.join(self.app_home, "%s.sh" % prefix)
             self.node.run_and_wait(command, self.run_home,
                     shfile = shfile, 
                     overwrite = False,
-                    pidfile = "deploy_pidfile", 
-                    ecodefile = "deploy_exitcode", 
-                    stdout = "deploy_stdout", 
-                    stderr = "deploy_stderr")
-
-    def upload_sources(self, src_dir = None):
-        sources = self.get("sources")
+                    pidfile = "%s_pidfile" % prefix, 
+                    ecodefile = "%s_exitcode" % prefix, 
+                    stdout = "%s_stdout" % prefix, 
+                    stderr = "%s_stderr" % prefix)
+
+    def upload_sources(self, sources = None, src_dir = None):
+        if not sources:
+            sources = self.get("sources")
    
         command = ""
 
@@ -369,7 +391,7 @@ class LinuxApplication(ResourceManager):
         if sources:
             self.info("Uploading sources ")
 
-            sources = sources.split(' ')
+            sources = map(str.strip, sources.split(";"))
 
             # Separate sources that should be downloaded from 
             # the web, from sources that should be uploaded from
@@ -400,34 +422,38 @@ class LinuxApplication(ResourceManager):
             command = self.replace_paths(command)
        
             if sources:
-                sources = ' '.join(sources)
+                sources = ';'.join(sources)
                 self.node.upload(sources, src_dir, overwrite = False)
 
         return command
 
-    def upload_files(self):
-        files = self.get("files")
+    def upload_files(self, files = None):
+        if not files:
+            files = self.get("files")
 
         if files:
             self.info("Uploading files %s " % files)
             self.node.upload(files, self.node.share_dir, overwrite = False)
 
-    def upload_libraries(self):
-        libs = self.get("libs")
+    def upload_libraries(self, libs = None):
+        if not libs:
+            libs = self.get("libs")
 
         if libs:
             self.info("Uploading libraries %s " % libaries)
             self.node.upload(libs, self.node.lib_dir, overwrite = False)
 
-    def upload_binaries(self):
-        bins = self.get("bins")
+    def upload_binaries(self, bins = None):
+        if not bins:
+            bins = self.get("bins")
 
         if bins:
             self.info("Uploading binaries %s " % binaries)
             self.node.upload(bins, self.node.bin_dir, overwrite = False)
 
-    def upload_code(self):
-        code = self.get("code")
+    def upload_code(self, code = None):
+        if not code:
+            code = self.get("code")
 
         if code:
             self.info("Uploading code")
@@ -435,15 +461,21 @@ class LinuxApplication(ResourceManager):
             dst = os.path.join(self.app_home, "code")
             self.node.upload(code, dst, overwrite = False, text = True)
 
-    def upload_stdin(self):
-        stdin = self.get("stdin")
+    def upload_stdin(self, stdin = None):
+        if not stdin:
+           stdin = self.get("stdin")
+
         if stdin:
             # create dir for sources
             self.info("Uploading stdin")
             
             # upload stdin file to ${SHARE_DIR} directory
-            basename = os.path.basename(stdin)
-            dst = os.path.join(self.node.share_dir, basename)
+            if os.path.isfile(stdin):
+                basename = os.path.basename(stdin)
+                dst = os.path.join(self.node.share_dir, basename)
+            else:
+                dst = os.path.join(self.app_home, "stdin")
+
             self.node.upload(stdin, dst, overwrite = False, text = True)
 
             # create "stdin" symlink on ${APP_HOME} directory
@@ -453,14 +485,17 @@ class LinuxApplication(ResourceManager):
 
             return command
 
-    def install_dependencies(self):
-        depends = self.get("depends")
+    def install_dependencies(self, depends = None):
+        if not depends:
+            depends = self.get("depends")
+
         if depends:
             self.info("Installing dependencies %s" % depends)
             return self.node.install_packages_command(depends)
 
-    def build(self):
-        build = self.get("build")
+    def build(self, build = None):
+        if not build:
+            build = self.get("build")
 
         if build:
             self.info("Building sources ")
@@ -468,8 +503,9 @@ class LinuxApplication(ResourceManager):
             # replace application specific paths in the command
             return self.replace_paths(build)
 
-    def install(self):
-        install = self.get("install")
+    def install(self, install = None):
+        if not install:
+            install = self.get("install")
 
         if install:
             self.info("Installing sources ")
@@ -609,11 +645,15 @@ class LinuxApplication(ResourceManager):
     def do_release(self):
         self.info("Releasing resource")
 
+        self.do_stop()
+        
         tear_down = self.get("tearDown")
         if tear_down:
             self.node.execute(tear_down)
 
-        self.do_stop()
+        hard_release = self.get("hardRelease")
+        if hard_release:
+            self.node.rmdir(self.app_home)
 
         super(LinuxApplication, self).do_release()
         
@@ -671,6 +711,7 @@ class LinuxApplication(ResourceManager):
     def execute_command(self, command, 
             env = None,
             sudo = False,
+            tty = False,
             forward_x11 = False,
             blocking = False):
 
@@ -682,6 +723,7 @@ class LinuxApplication(ResourceManager):
 
         return self.node.execute(command,
                 sudo = sudo,
+                tty = tty,
                 forward_x11 = forward_x11,
                 blocking = blocking)