Ticket #22: complitid
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Fri, 27 May 2011 10:51:48 +0000 (12:51 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Fri, 27 May 2011 10:51:48 +0000 (12:51 +0200)
src/nepi/testbeds/planetlab/execute.py
src/nepi/testbeds/planetlab/node.py
test/testbeds/planetlab/execute.py

index d9506f5..15065b8 100644 (file)
@@ -6,6 +6,7 @@ from nepi.core import testbed_impl
 from nepi.util.constants import TIME_NOW
 import os
 import time
+import resourcealloc
 
 class TestbedController(testbed_impl.TestbedController):
     def __init__(self, testbed_version):
@@ -80,12 +81,11 @@ class TestbedController(testbed_impl.TestbedController):
         super(TestbedController, self).do_preconfigure()
 
     def do_resource_discovery(self):
-        # Do what?
-
-        # Provisional algo:
+        to_provision = self._to_provision = set()
+        
+        # Initial algo:
         #   look for perfectly defined nodes
         #   (ie: those with only one candidate)
-        to_provision = self._to_provision = set()
         for guid, node in self._elements.iteritems():
             if isinstance(node, self._node.Node) and node._node_id is None:
                 # Try existing nodes first
@@ -98,13 +98,43 @@ class TestbedController(testbed_impl.TestbedController):
                     # Try again including unassigned nodes
                     candidates = node.find_candidates()
                     if len(candidates) > 1:
-                        raise RuntimeError, "Cannot assign resources for node %s, too many candidates" % (guid,)
+                        continue
                     if len(candidates) == 1:
                         node_id = iter(candidates).next()
                         node.assign_node_id(node_id)
                         to_provision.add(node_id)
                     elif not candidates:
                         raise RuntimeError, "Cannot assign resources for node %s, no candidates" % (guid,)
+        
+        # Now do the backtracking search for a suitable solution
+        # First with existing slice nodes
+        reqs = []
+        nodes = []
+        for guid, node in self._elements.iteritems():
+            if isinstance(node, self._node.Node) and node._node_id is None:
+                # Try existing nodes first
+                # If we have only one candidate, simply use it
+                candidates = node.find_candidates(
+                    filter_slice_id = self.slice_id)
+                reqs.append(candidates)
+                nodes.append(node)
+        
+        if nodes and reqs:
+            try:
+                solution = resourcealloc.alloc(reqs)
+            except resourcealloc.ResourceAllocationError:
+                # Failed, try again with all nodes
+                reqs = []
+                for node in nodes:
+                    candidates = node.find_candidates()
+                    reqs.append(candidates)
+                
+                solution = resourcealloc.alloc(reqs)
+                to_provision.update(solution)
+            
+            # Do assign nodes
+            for node, node_id in zip(nodes, solution):
+                node.assign_node_id(node_id)
 
     def do_provisioning(self):
         if self._to_provision:
index 0b5b9de..08ec7a7 100644 (file)
@@ -9,6 +9,7 @@ import time
 import os
 import collections
 import cStringIO
+import resourcealloc
 
 from nepi.util import server
 
@@ -108,6 +109,10 @@ class Node(object):
         if filter_slice_id:
             basefilters['|slice_ids'] = (filter_slice_id,)
         
+        # only pick healthy nodes
+        basefilters['run_level'] = 'boot'
+        basefilters['boot_state'] = 'boot'
+        
         # keyword-only "pseudofilters"
         extra = {}
         if self.site:
index 920ef03..ecff9e6 100755 (executable)
@@ -509,6 +509,63 @@ echo 'OKIDOKI'
         
         # asserts at the end, to make sure there's proper cleanup
         self.assertEqual(ping_result, "")
+
+    @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
+    def test_discovery(self):
+        instance = self.make_instance()
+        
+        instance.defer_create(2, "Node")
+        instance.defer_create_set(2, "operatingSystem", "f12")
+        instance.defer_create(3, "Node")
+        instance.defer_create_set(3, "operatingSystem", "f12")
+        instance.defer_create(4, "NodeInterface")
+        instance.defer_connect(2, "devs", 4, "node")
+        instance.defer_create(5, "NodeInterface")
+        instance.defer_connect(3, "devs", 5, "node")
+        instance.defer_create(6, "Internet")
+        instance.defer_connect(4, "inet", 6, "devs")
+        instance.defer_connect(5, "inet", 6, "devs")
+        instance.defer_create(7, "Application")
+        instance.defer_create_set(7, "command", "ping -qc1 {#[GUID-5].addr[0].[Address]#}")
+        instance.defer_add_trace(7, "stdout")
+        instance.defer_add_trace(7, "stderr")
+        instance.defer_connect(7, "node", 2, "apps")
+
+        comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
+
+--- .* ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
+"""
+
+        try:
+            instance.do_setup()
+            instance.do_create()
+            instance.do_connect_init()
+            instance.do_connect_compl()
+            instance.do_preconfigure()
+            
+            # Manually replace netref
+            instance.set(7, "command",
+                instance.get(7, "command")
+                    .replace("{#[GUID-5].addr[0].[Address]#}", 
+                        instance.get_address(5, 0, "Address") )
+            )
+
+            instance.do_configure()
+            
+            instance.do_prestart()
+            instance.start()
+            while instance.status(7) != STATUS_FINISHED:
+                time.sleep(0.5)
+            ping_result = instance.trace(7, "stdout") or ""
+            instance.stop()
+        finally:
+            instance.shutdown()
+
+        # asserts at the end, to make sure there's proper cleanup
+        self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
+            "Unexpected trace:\n" + ping_result)
+        
         
 
 if __name__ == '__main__':