Merge "Migrate test_load_balancer_basic to tempest client"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 07cb028..48eff84 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -896,6 +896,41 @@
 
         return rules
 
+    def _create_pool(self, lb_method, protocol, subnet_id):
+        """Wrapper utility that returns a test pool."""
+        client = self.network_client
+        name = data_utils.rand_name('pool')
+        _, resp_pool = client.create_pool(protocol=protocol, name=name,
+                                          subnet_id=subnet_id,
+                                          lb_method=lb_method)
+        pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
+        self.assertEqual(pool['name'], name)
+        self.addCleanup(self.delete_wrapper, pool.delete)
+        return pool
+
+    def _create_member(self, address, protocol_port, pool_id):
+        """Wrapper utility that returns a test member."""
+        client = self.network_client
+        _, resp_member = client.create_member(protocol_port=protocol_port,
+                                              pool_id=pool_id,
+                                              address=address)
+        member = net_resources.DeletableMember(client=client,
+                                               **resp_member['member'])
+        self.addCleanup(self.delete_wrapper, member.delete)
+        return member
+
+    def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
+        """Wrapper utility that returns a test vip."""
+        client = self.network_client
+        name = data_utils.rand_name('vip')
+        _, resp_vip = client.create_vip(protocol=protocol, name=name,
+                                        subnet_id=subnet_id, pool_id=pool_id,
+                                        protocol_port=protocol_port)
+        vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
+        self.assertEqual(vip['name'], name)
+        self.addCleanup(self.delete_wrapper, vip.delete)
+        return vip
+
     def _ssh_to_server(self, server, private_key):
         ssh_login = CONF.compute.image_ssh_user
         return self.get_remote_client(server,
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 35e50e8..5e83ff9 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -28,7 +28,7 @@
 config = config.CONF
 
 
-class TestLoadBalancerBasic(manager.NetworkScenarioTest):
+class TestLoadBalancerBasic(manager.NeutronScenarioTest):
 
     """
     This test checks basic load balancing.
@@ -72,7 +72,7 @@
         super(TestLoadBalancerBasic, self).setUp()
         self.server_ips = {}
         self.server_fixed_ips = {}
-        self._create_security_group()
+        self._create_security_group_for_test()
         self._set_net_and_subnet()
 
     def _set_net_and_subnet(self):
@@ -103,8 +103,8 @@
             subnet = self._list_subnets(network_id=self.network['id'])[0]
             self.subnet = net_common.AttributeDict(subnet)
 
-    def _create_security_group(self):
-        self.security_group = self._create_security_group_neutron(
+    def _create_security_group_for_test(self):
+        self.security_group = self._create_security_group(
             tenant_id=self.tenant_id)
         self._create_security_group_rules_for_port(self.port1)
         self._create_security_group_rules_for_port(self.port2)
@@ -117,35 +117,35 @@
             'port_range_max': port,
         }
         self._create_security_group_rule(
-            client=self.network_client,
             secgroup=self.security_group,
             tenant_id=self.tenant_id,
             **rule)
 
     def _create_server(self, name):
-        keypair = self.create_keypair(name='keypair-%s' % name)
-        security_groups = [self.security_group.name]
+        keypair = self.create_keypair()
+        security_groups = [self.security_group]
         create_kwargs = {
             'nics': [
                 {'net-id': self.network['id']},
             ],
-            'key_name': keypair.name,
+            'key_name': keypair['name'],
             'security_groups': security_groups,
         }
-        server = self.create_server(name=name,
-                                    create_kwargs=create_kwargs)
-        self.servers_keypairs[server.id] = keypair
         net_name = self.network['name']
+        server = self.create_server(name=name, create_kwargs=create_kwargs)
+        self.servers_keypairs[server['id']] = keypair
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             public_network_id = config.network.public_network_id
             floating_ip = self._create_floating_ip(
                 server, public_network_id)
             self.floating_ips[floating_ip] = server
-            self.server_ips[server.id] = floating_ip.floating_ip_address
+            self.server_ips[server['id']] = floating_ip.floating_ip_address
         else:
-            self.server_ips[server.id] = server.networks[net_name][0]
-        self.server_fixed_ips[server.id] = server.networks[net_name][0]
+            self.server_ips[server['id']] =\
+                server['addresses'][net_name][0]['addr']
+        self.server_fixed_ips[server['id']] =\
+            server['addresses'][net_name][0]['addr']
         self.assertTrue(self.servers_keypairs)
         return server
 
@@ -162,8 +162,8 @@
         2. Start two http backends listening on ports 80 and 88 respectively
         """
         for server_id, ip in self.server_ips.iteritems():
-            private_key = self.servers_keypairs[server_id].private_key
-            server_name = self.compute_client.servers.get(server_id).name
+            private_key = self.servers_keypairs[server_id]['private_key']
+            server_name = self.servers_client.get_server(server_id)[1]['name']
             username = config.scenario.ssh_user
             ssh_client = self.get_remote_client(
                 server_or_ip=ip,
@@ -269,11 +269,7 @@
                                     protocol_port=80,
                                     subnet_id=self.subnet.id,
                                     pool_id=self.pool.id)
-        self.status_timeout(NeutronRetriever(self.network_client,
-                                             self.network_client.vip_path,
-                                             net_common.DeletableVip),
-                            self.vip.id,
-                            expected_status='ACTIVE')
+        self.vip.wait_for_status('ACTIVE')
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             self._assign_floating_ip_to_vip(self.vip)
@@ -286,8 +282,8 @@
         # vip port - see https://bugs.launchpad.net/neutron/+bug/1163569
         # However the linuxbridge-agent does, and it is necessary to add a
         # security group with a rule that allows tcp port 80 to the vip port.
-        body = {'port': {'security_groups': [self.security_group.id]}}
-        self.network_client.update_port(self.vip.port_id, body)
+        self.network_client.update_port(
+            self.vip.port_id, security_groups=[self.security_group.id])
 
     def _check_load_balancing(self):
         """
@@ -318,27 +314,3 @@
         self._start_servers()
         self._create_load_balancer()
         self._check_load_balancing()
-
-
-class NeutronRetriever(object):
-    """
-    Helper class to make possible handling neutron objects returned by GET
-    requests as attribute dicts.
-
-    Whet get() method is called, the returned dictionary is wrapped into
-    a corresponding DeletableResource class which provides attribute access
-    to dictionary values.
-
-    Usage:
-        This retriever is used to allow using status_timeout from
-        tempest.manager with Neutron objects.
-    """
-
-    def __init__(self, network_client, path, resource):
-        self.network_client = network_client
-        self.path = path
-        self.resource = resource
-
-    def get(self, thing_id):
-        obj = self.network_client.get(self.path % thing_id)
-        return self.resource(client=self.network_client, **obj.values()[0])
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
index 94ba5aa..5ad5f37 100644
--- a/tempest/services/network/network_client_base.py
+++ b/tempest/services/network/network_client_base.py
@@ -13,6 +13,7 @@
 import time
 import urllib
 
+from tempest.common.utils import misc
 from tempest import config
 from tempest import exceptions
 
@@ -227,3 +228,39 @@
         except exceptions.NotFound:
             return True
         return False
+
+    def wait_for_resource_status(self, fetch, status, interval=None,
+                                 timeout=None):
+        """
+        @summary: Waits for a network resource to reach a status
+        @param fetch: the callable to be used to query the resource status
+        @type fecth: callable that takes no parameters and returns the resource
+        @param status: the status that the resource has to reach
+        @type status: String
+        @param interval: the number of seconds to wait between each status
+          query
+        @type interval: Integer
+        @param timeout: the maximum number of seconds to wait for the resource
+          to reach the desired status
+        @type timeout: Integer
+        """
+        if not interval:
+            interval = self.build_interval
+        if not timeout:
+            timeout = self.build_timeout
+        start_time = time.time()
+
+        while time.time() - start_time <= timeout:
+            resource = fetch()
+            if resource['status'] == status:
+                return
+            time.sleep(interval)
+
+        # At this point, the wait has timed out
+        message = 'Resource %s' % (str(resource))
+        message += ' failed to reach status %s' % status
+        message += ' within the required time %s' % timeout
+        caller = misc.find_test_caller()
+        if caller:
+            message = '(%s) %s' % (caller, message)
+        raise exceptions.TimeoutException(message)
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index b2feb87..2b182d0 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -51,9 +51,19 @@
     def delete(self):
         return
 
+    @abc.abstractmethod
+    def show(self):
+        return
+
     def __hash__(self):
         return hash(self.id)
 
+    def wait_for_status(self, status):
+        if not hasattr(self, 'status'):
+            return
+
+        return self.client.wait_for_resource_status(self.show, status)
+
 
 class DeletableNetwork(DeletableResource):
 
@@ -161,3 +171,8 @@
 
     def delete(self):
         self.client.delete_vip(self.id)
+
+    def show(self):
+        _, result = self.client.show_vip(self.id)
+        super(DeletableVip, self).update(**result['vip'])
+        return self