You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2013/01/07 06:34:36 UTC

svn commit: r1429674 - in /libcloud/trunk: CHANGES libcloud/compute/base.py libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml libcloud/test/compute/test_deployment.py

Author: tomaz
Date: Mon Jan  7 05:34:36 2013
New Revision: 1429674

URL: http://svn.apache.org/viewvc?rev=1429674&view=rev
Log:
Change _wait_until_running method so it supports waiting on multiple nodes
and make it public (wait_until_running).

Contributed by Nick Bailey, part of LIBCLOUD-274.

Added:
    libcloud/trunk/libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml
Modified:
    libcloud/trunk/CHANGES
    libcloud/trunk/libcloud/compute/base.py
    libcloud/trunk/libcloud/test/compute/test_deployment.py

Modified: libcloud/trunk/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1429674&r1=1429673&r2=1429674&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Mon Jan  7 05:34:36 2013
@@ -92,6 +92,10 @@ Changes with Apache Libcloud in developm
       your code if you rely on the old behavior.
       [Tomaz Muraus, Marcin Kuzminski]
 
+    - Change _wait_until_running method so it supports waiting on multiple nodes
+      and make it public (wait_until_running). (LIBCLOUD-274)
+      [Nick Bailey]
+
   *) Storage
 
     - Add a new local storage driver.

Modified: libcloud/trunk/libcloud/compute/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/base.py?rev=1429674&r1=1429673&r2=1429674&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/base.py (original)
+++ libcloud/trunk/libcloud/compute/base.py Mon Jan  7 05:34:36 2013
@@ -650,10 +650,10 @@ class NodeDriver(BaseDriver):
         try:
             # Wait until node is up and running and has IP assigned
             ssh_interface = kwargs.get('ssh_interface', 'public_ips')
-            node, ip_addresses = self._wait_until_running(
-                node=node,
+            node, ip_addresses = self.wait_until_running(
+                nodes=[node],
                 wait_period=3, timeout=NODE_ONLINE_WAIT_TIMEOUT,
-                ssh_interface=ssh_interface)
+                ssh_interface=ssh_interface)[0]
 
             if password:
                 node.extra['password'] = password
@@ -755,11 +755,19 @@ class NodeDriver(BaseDriver):
 
     def _wait_until_running(self, node, wait_period=3, timeout=600,
                             ssh_interface='public_ips', force_ipv4=True):
+        # This is here for backward compatibility and will be removed in the
+        # next major release
+        return wait_until_running(nodes=[node], wait_period=wait_period,
+                                  timeout=timeout, ssh_interface=ssh_interface,
+                                  force_ipv4=force_ipv4)
+
+    def wait_until_running(self, nodes, wait_period=3, timeout=600,
+                           ssh_interface='public_ips', force_ipv4=True):
         """
-        Block until node is fully booted and has an IP address assigned.
+        Block until the given nodes are fully booted and have an IP address assigned.
 
-        @keyword    node: Node instance.
-        @type       node: C{Node}
+        @keyword    nodes: list of node instances.
+        @type       nodes: C{List} of L{Node}
 
         @keyword    wait_period: How many seconds to between each loop
                                  iteration (default is 3)
@@ -777,8 +785,12 @@ class NodeDriver(BaseDriver):
         @keyword    force_ipv4: Ignore ipv6 IP addresses (default is True).
         @type       force_ipv4: C{bool}
 
-        @return: C{(Node, ip_addresses)} tuple of Node instance and
+        @return: C{[(Node, ip_addresses)]} list of tuple of Node instance and
                  list of ip_address on success.
+
+        @return: List of tuple of Node instance and list of ip_address on
+                 success (node, ip_addresses).
+        @rtype: C{list} of C{tuple}
         """
         def is_supported(address):
             """Return True for supported address"""
@@ -798,19 +810,22 @@ class NodeDriver(BaseDriver):
             raise ValueError('ssh_interface argument must either be' +
                              'public_ips or private_ips')
 
+        uuids = set([n.uuid for n in nodes])
         while time.time() < end:
             nodes = self.list_nodes()
-            nodes = list([n for n in nodes if n.uuid == node.uuid])
+            nodes = list([n for n in nodes if n.uuid in uuids])
 
-            if len(nodes) > 1:
-                raise LibcloudError(value=('Booted single node[%s], ' % node
-                                    + 'but multiple nodes have same UUID'),
+            if len(nodes) > len(uuids):
+                found_uuids = [n.uuid for n in nodes]
+                raise LibcloudError(value=('Unable to match specified uuids ' +
+                                           '(%s) with existing nodes. Found ' % uuids +
+                                           'multiple nodes with same uuid: (%s)' % found_uuids),
                                     driver=self)
 
-            if (len(nodes) == 1 and nodes[0].state == NodeState.RUNNING and
-                    filter_addresses(getattr(nodes[0], ssh_interface))):
-                return (nodes[0], filter_addresses(getattr(nodes[0],
-                                                   ssh_interface)))
+            running_nodes = [n for n in nodes if n.state == NodeState.RUNNING]
+            addresses = [filter_addresses(getattr(n, ssh_interface)) for n in running_nodes]
+            if len(running_nodes) == len(uuids) == len(addresses):
+                return list(zip(running_nodes, addresses))
             else:
                 time.sleep(wait_period)
                 continue

Added: libcloud/trunk/libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml?rev=1429674&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/openstack/v1_slug_servers_detail_deployment_multiple_nodes.xml Mon Jan  7 05:34:36 2013
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<servers xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
+  <server status="ACTIVE" progress="100" hostId="9dd380940fcbe39cb30255ed4664f1f3" flavorId="1" imageId="11" id="12345" name="racktest">
+    <metadata/>
+    <addresses>
+      <public>
+    <ip addr="67.23.21.33"/>
+      </public>
+      <private>
+    <ip addr="10.176.168.218"/>
+      </private>
+    </addresses>
+ </server>
+ <server status="ACTIVE" progress="100" hostId="9dd380940fcbe39cb30255ed4664f1f3" flavorId="1" imageId="11" id="123456" name="racktest">
+    <metadata/>
+    <addresses>
+      <public>
+    <ip addr="67.23.21.34"/>
+      </public>
+      <private>
+    <ip addr="10.176.168.219"/>
+      </private>
+    </addresses>
+  </server>
+
+</servers>

Modified: libcloud/trunk/libcloud/test/compute/test_deployment.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/test_deployment.py?rev=1429674&r1=1429673&r2=1429674&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/compute/test_deployment.py (original)
+++ libcloud/trunk/libcloud/test/compute/test_deployment.py Mon Jan  7 05:34:36 2013
@@ -70,6 +70,9 @@ class DeploymentTests(unittest.TestCase)
         self.node = Node(id=12345, name='test', state=NodeState.RUNNING,
                    public_ips=['1.2.3.4'], private_ips=['1.2.3.5'],
                    driver=Rackspace)
+        self.node2 = Node(id=123456, name='test', state=NodeState.RUNNING,
+                          public_ips=['1.2.3.4'], private_ips=['1.2.3.5'],
+                          driver=Rackspace)
 
     def test_multi_step_deployment(self):
         msd = MultiStepDeployment()
@@ -139,28 +142,28 @@ class DeploymentTests(unittest.TestCase)
             self.fail('TypeError was not thrown')
 
     def test_wait_until_running_running_instantly(self):
-        node2, ips = self.driver._wait_until_running(node=self.node, wait_period=1,
-                                                     timeout=10)
+        node2, ips = self.driver.wait_until_running(nodes=[self.node], wait_period=1,
+                                                     timeout=10)[0]
         self.assertEqual(self.node.uuid, node2.uuid)
         self.assertEqual(['67.23.21.33'], ips)
 
     def test_wait_until_running_running_after_1_second(self):
         RackspaceMockHttp.type = '1_SECOND_DELAY'
-        node2, ips = self.driver._wait_until_running(node=self.node, wait_period=1,
-                                                     timeout=10)
+        node2, ips = self.driver.wait_until_running(nodes=[self.node], wait_period=1,
+                                                     timeout=10)[0]
         self.assertEqual(self.node.uuid, node2.uuid)
         self.assertEqual(['67.23.21.33'], ips)
 
     def test_wait_until_running_running_after_1_second_private_ips(self):
         RackspaceMockHttp.type = '1_SECOND_DELAY'
-        node2, ips = self.driver._wait_until_running(node=self.node, wait_period=1,
-                                                     timeout=10, ssh_interface='private_ips')
+        node2, ips = self.driver.wait_until_running(nodes=[self.node], wait_period=1,
+                                                     timeout=10, ssh_interface='private_ips')[0]
         self.assertEqual(self.node.uuid, node2.uuid)
         self.assertEqual(['10.176.168.218'], ips)
 
     def test_wait_until_running_invalid_ssh_interface_argument(self):
         try:
-            self.driver._wait_until_running(node=self.node, wait_period=1,
+            self.driver.wait_until_running(nodes=[self.node], wait_period=1,
                                             ssh_interface='invalid')
         except ValueError:
             pass
@@ -171,7 +174,7 @@ class DeploymentTests(unittest.TestCase)
         RackspaceMockHttp.type = 'TIMEOUT'
 
         try:
-            self.driver._wait_until_running(node=self.node, wait_period=0.5,
+            self.driver.wait_until_running(nodes=[self.node], wait_period=0.5,
                                             timeout=1)
         except LibcloudError:
             e = sys.exc_info()[1]
@@ -183,8 +186,8 @@ class DeploymentTests(unittest.TestCase)
         RackspaceMockHttp.type = 'MISSING'
 
         try:
-            self.driver._wait_until_running(node=self.node, wait_period=0.5,
-                                            timeout=1)
+            self.driver.wait_until_running(nodes=[self.node], wait_period=0.5,
+                                           timeout=1)
         except LibcloudError:
             e = sys.exc_info()[1]
             self.assertTrue(e.value.find('Timed out after 1 second') != -1)
@@ -195,14 +198,24 @@ class DeploymentTests(unittest.TestCase)
         RackspaceMockHttp.type = 'SAME_UUID'
 
         try:
-            self.driver._wait_until_running(node=self.node, wait_period=0.5,
+            self.driver.wait_until_running(nodes=[self.node], wait_period=0.5,
                                             timeout=1)
         except LibcloudError:
             e = sys.exc_info()[1]
-            self.assertTrue(e.value.find('multiple nodes have same UUID') != -1)
+            self.assertTrue(e.value.find('Unable to match specified uuids') != -1)
         else:
             self.fail('Exception was not thrown')
 
+    def test_wait_until_running_running_wait_for_multiple_nodes(self):
+        RackspaceMockHttp.type = 'MULTIPLE_NODES'
+
+        nodes = self.driver.wait_until_running(nodes=[self.node, self.node2], wait_period=0.5,
+                                               timeout=1)
+        self.assertEqual(self.node.uuid, nodes[0][0].uuid)
+        self.assertEqual(self.node2.uuid, nodes[1][0].uuid)
+        self.assertEqual(['67.23.21.33'], nodes[0][1])
+        self.assertEqual(['67.23.21.34'], nodes[1][1])
+
     def test_ssh_client_connect_success(self):
         mock_ssh_client = Mock()
         mock_ssh_client.return_value = None
@@ -400,6 +413,10 @@ class RackspaceMockHttp(MockHttp):
         body = self.fixtures.load('v1_slug_servers_detail_deployment_same_uuid.xml')
         return (httplib.OK, body, XML_HEADERS, httplib.responses[httplib.OK])
 
+    def _v1_0_slug_servers_detail_MULTIPLE_NODES(self, method, url, body, headers):
+        body = self.fixtures.load('v1_slug_servers_detail_deployment_multiple_nodes.xml')
+        return (httplib.OK, body, XML_HEADERS, httplib.responses[httplib.OK])
+
 
 if __name__ == '__main__':
     sys.exit(unittest.main())