Slice cleanup: dedicated slices can be cleaned up thoroughly.
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 15:34:19 +0000 (17:34 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 15:34:19 +0000 (17:34 +0200)
The user only has to set the appropriate testbed attribute

src/nepi/testbeds/planetlab/execute.py
src/nepi/testbeds/planetlab/node.py

index dbe0fb5..7860790 100644 (file)
@@ -129,6 +129,8 @@ class TestbedController(testbed_impl.TestbedController):
             get_attribute_value("tapPortBase")
         self.p2pDeployment = self._attributes.\
             get_attribute_value("p2pDeployment")
+        self.dedicatedSlice = self._attributes.\
+            get_attribute_value("dedicatedSlice")
         
         self._logger.setLevel(getattr(logging,self.logLevel))
         
@@ -493,22 +495,19 @@ class TestbedController(testbed_impl.TestbedController):
         for trace in self._traces.itervalues():
             trace.close()
         
-        runner = ParallelRun(16)
-        runner.start()
-        for element in self._elements.itervalues():
-            # invoke cleanup hooks
-            if hasattr(element, 'cleanup'):
-                runner.put(element.cleanup)
-        runner.join()
-        
-        runner = ParallelRun(16)
-        runner.start()
-        for element in self._elements.itervalues():
-            # invoke destroy hooks
-            if hasattr(element, 'destroy'):
-                runner.put(element.destroy)
-        runner.join()
+        def invokeif(action, testbed, guid):
+            element = self._elements[guid]
+            if hasattr(element, action):
+                getattr(element, action)()
         
+        self._do_in_factory_order(
+            functools.partial(invokeif, 'cleanup'),
+            metadata.shutdown_order)
+
+        self._do_in_factory_order(
+            functools.partial(invokeif, 'destroy'),
+            metadata.shutdown_order)
+            
         self._elements.clear()
         self._traces.clear()
 
@@ -626,7 +625,9 @@ class TestbedController(testbed_impl.TestbedController):
         return app
 
     def _make_node(self, parameters):
-        return self._make_generic(parameters, self._node.Node)
+        node = self._make_generic(parameters, self._node.Node)
+        node.enable_cleanup = self.dedicatedSlice
+        return node
 
     def _make_node_iface(self, parameters):
         return self._make_generic(parameters, self._interfaces.NodeIface)
index 4d055c1..1101bfe 100644 (file)
@@ -114,6 +114,7 @@ class Node(object):
         self.ident_path = None
         self.server_key = None
         self.home_path = None
+        self.enable_cleanup = False
         
         # Those are filled when an actual node is allocated
         self._node_id = None
@@ -422,6 +423,10 @@ class Node(object):
                 # If we're above that delay, the unresponsiveness is not due
                 # to this delay.
                 raise UnresponsiveNodeError, "Unresponsive host %s" % (self.hostname,)
+        
+        # Ensure the node is clean (no apps running that could interfere with operations)
+        if self.enable_cleanup:
+            self.do_cleanup()
     
     def wait_dependencies(self, pidprobe=1, probe=0.5, pidmax=10, probemax=10):
         # Wait for the p2p installer
@@ -449,6 +454,28 @@ class Node(object):
         else:
             return False
     
+    def destroy(self):
+        if self.enable_cleanup:
+            self.do_cleanup()
+    
+    def do_cleanup(self):
+        self._logger.info("Cleaning up %s", self.hostname)
+
+        (out,err),proc = server.popen_ssh_command(
+            # Some apps need two kills
+            "sudo -S killall -u %(slicename)s ; sudo -S killall -u root ; "
+            "sudo -S killall -u %(slicename)s ; sudo -S killall -u root" % {
+                'slicename' : self.slicename ,
+            },
+            host = self.hostname,
+            port = None,
+            user = self.slicename,
+            agent = None,
+            ident_key = self.ident_path,
+            server_key = self.server_key
+            )
+        proc.wait()
+    
     def prepare_dependencies(self):
         # Configure p2p yum dependency installer
         if self.required_packages and not self._installed:
@@ -484,9 +511,10 @@ class Node(object):
                     "- PL can only handle rules over virtual interfaces. Candidates are: %s" % (route,devs)
         
         self._logger.info("Setting up routes for %s", self.hostname)
+        self._logger.debug("Routes for %s:\n\t%s", self.hostname, '\n\t'.join(rules))
         
         (out,err),proc = server.popen_ssh_command(
-            "( sudo -S bash -c 'cat /vsys/vroute.out >&2' & ) ; sudo -S bash -c 'cat > /vsys/vroute.in' ; sleep 0.1" % dict(
+            "( sudo -S bash -c 'cat /vsys/vroute.out >&2' & ) ; sudo -S bash -c 'cat > /vsys/vroute.in' ; sleep 0.5" % dict(
                 home = server.shell_escape(self.home_path)),
             host = self.hostname,
             port = None,
@@ -499,6 +527,8 @@ class Node(object):
         
         if proc.wait() or err:
             raise RuntimeError, "Could not set routes (%s) errors: %s%s" % (rules,out,err)
+        elif out or err:
+            logger.debug("Routes said: %s%s", out, err)