Ticket #29: introduce some "standard" box attributes to support testbed-in-testbed...
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Mon, 2 May 2011 16:42:51 +0000 (18:42 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Mon, 2 May 2011 16:42:51 +0000 (18:42 +0200)
src/nepi/testbeds/planetlab/metadata_v01.py
src/nepi/testbeds/planetlab/node.py
src/nepi/util/constants.py
src/nepi/util/proxy.py
src/nepi/util/server.py

index 9c85c04..27d9679 100644 (file)
@@ -8,7 +8,7 @@ from nepi.core import metadata
 from nepi.core.attributes import Attribute
 from nepi.util import validation
 from nepi.util.constants import STATUS_NOT_STARTED, STATUS_RUNNING, \
-        STATUS_FINISHED
+        STATUS_FINISHED, ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP
 
 import functools
 import os
@@ -679,6 +679,13 @@ attributes = dict({
                 "flags": Attribute.DesignOnly,
                 "validation_function": validation.is_string
             }),
+    ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP: dict({
+                "name": ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
+                "help": "Commands to set up the environment needed to run NEPI testbeds",
+                "type": Attribute.STRING,
+                "flags": Attribute.Invisible | Attribute.ReadOnly,
+                "validation_function": validation.is_string
+            }),
     
     "netpipe_mode": dict({      
                 "name": "mode",
@@ -792,6 +799,9 @@ factories_info = dict({
                 "max_reliability",
                 "min_bandwidth",
                 "max_bandwidth",
+                
+                # NEPI-in-NEPI attributes
+                ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
             ],
             "connector_types": ["devs", "apps", "pipes", "deps"]
        }),
index 245e636..73593af 100644 (file)
@@ -8,6 +8,7 @@ import rspawn
 import time
 import os
 import collections
+import cStringIO
 
 from nepi.util import server
 
@@ -68,6 +69,22 @@ class Node(object):
         # Those are filled when an actual node is allocated
         self._node_id = None
     
+    @property
+    def _nepi_testbed_environment_setup(self):
+        command = cStringIO.StringIO()
+        command.write('PYTHONPATH=$PYTHONPATH:%s' % (
+            ':'.join(["${HOME}/"+server.shell_escape(s) for s in self.pythonpath])
+        ))
+        command.write(' PATH=$PATH:%s' % (
+            ':'.join(["${HOME}/"+server.shell_escape(s) for s in self.pythonpath])
+        ))
+        if self.node.env:
+            for envkey, envvals in self.node.env.iteritems():
+                for envval in envvals:
+                    command.write(' %s=%s' % (envkey, envval))
+        command.write(self.command)
+        return command.getvalue()
+    
     def build_filters(self, target_filters, filter_map):
         for attr, tag in filter_map.iteritems():
             value = getattr(self, attr, None)
index cb94c2e..ac23fed 100644 (file)
@@ -20,3 +20,6 @@ TESTBED_STATUS_STOPPED = 7
 
 TIME_NOW = "0s"
 
+
+ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP = "_nepi_testbed_environment_setup"
+
index 9b7b447..1be195a 100644 (file)
@@ -4,7 +4,7 @@
 import base64
 from nepi.core.attributes import AttributesMap, Attribute
 from nepi.util import server, validation
-from nepi.util.constants import TIME_NOW
+from nepi.util.constants import TIME_NOW, ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP
 import getpass
 import cPickle
 import sys
@@ -317,6 +317,10 @@ def create_testbed_controller(testbed_id, testbed_version, access_config):
             else access_config.get_attribute_value("mode")
     launch = True if not access_config \
             else not access_config.get_attribute_value("recover")
+    environment_setup = access_config \
+            and access_config.has_attribute(ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP) \
+            and access_config.get_attribute_value(ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP) \
+            or ""
     if not mode or mode == AccessConfiguration.MODE_SINGLE_PROCESS:
         if not launch:
             raise ValueError, "Unsupported instantiation mode: %s with lanch=False" % (mode,)
@@ -326,7 +330,8 @@ def create_testbed_controller(testbed_id, testbed_version, access_config):
                 get_access_config_params(access_config)
         return TestbedControllerProxy(root_dir, log_level, testbed_id = testbed_id, 
                 testbed_version = testbed_version, host = host, port = port,
-                user = user, agent = agent, launch = launch)
+                user = user, agent = agent, launch = launch,
+                environment_setup = environment_setup)
     raise RuntimeError("Unsupported access configuration '%s'" % mode)
 
 def _build_testbed_controller(testbed_id, testbed_version):
@@ -770,7 +775,8 @@ class ExperimentControllerServer(server.Server):
 class TestbedControllerProxy(object):
     def __init__(self, root_dir, log_level, testbed_id = None, 
             testbed_version = None, launch = True, host = None, 
-            port = None, user = None, agent = None):
+            port = None, user = None, agent = None,
+            environment_setup = ""):
         if launch:
             if testbed_id == None or testbed_version == None:
                 raise RuntimeError("To launch a TesbedInstance server a \
@@ -783,7 +789,8 @@ class TestbedControllerProxy(object):
                         s.run()" % (root_dir, log_level, testbed_id, 
                                 testbed_version)
                 proc = server.popen_ssh_subprocess(python_code, host = host,
-                    port = port, user = user, agent = agent)
+                    port = port, user = user, agent = agent,
+                    environment_setup = environment_setup)
                 if proc.poll():
                     err = proc.stderr.read()
                     raise RuntimeError("Server could not be executed: %s" % \
@@ -1178,7 +1185,7 @@ class TestbedControllerProxy(object):
 class ExperimentControllerProxy(object):
     def __init__(self, root_dir, log_level, experiment_xml = None, 
             launch = True, host = None, port = None, user = None, 
-            agent = None):
+            agent = None, environment_setup = ""):
         if launch:
             # launch server
             if experiment_xml == None:
@@ -1191,7 +1198,8 @@ class ExperimentControllerProxy(object):
                         s = ExperimentControllerServer(%r, %r, %r);\
                         s.run()" % (root_dir, log_level, xml)
                 proc = server.popen_ssh_subprocess(python_code, host = host,
-                    port = port, user = user, agent = agent)
+                    port = port, user = user, agent = agent,
+                    environment_setup = environment_setup)
                 if proc.poll():
                     err = proc.stderr.read()
                     raise RuntimeError("Server could not be executed: %s" % \
index 7d4bd88..44c6408 100644 (file)
@@ -616,12 +616,16 @@ def popen_ssh_subprocess(python_code, host, port, user, agent,
         python_path = None,
         ident_key = None,
         server_key = None,
-        tty = False):
+        tty = False,
+        environment_setup = ""):
         if python_path:
             python_path.replace("'", r"'\''")
             cmd = """PYTHONPATH="$PYTHONPATH":'%s' """ % python_path
         else:
             cmd = ""
+        if environment_setup:
+            cmd += environment_setup
+            cmd += " "
         # Uncomment for debug (to run everything under strace)
         # We had to verify if strace works (cannot nest them)
         #cmd += "if strace echo >/dev/null 2>&1; then CMD='strace -ff -tt -s 200 -o strace.out'; else CMD=''; fi\n"