Merge "Add return one value to volume delete methods"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 234273b..02609ae 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -135,6 +135,9 @@
 # concurrent test processes. (boolean value)
 #locking_credentials_provider = false
 
+# Roles to assign to all users created by tempest (list value)
+#tempest_roles =
+
 
 [baremetal]
 
@@ -582,9 +585,6 @@
 # applies to user and project (string value)
 #admin_domain_name = <None>
 
-# Roles to assign to all users created by tempest (list value)
-#tempest_roles =
-
 
 [identity-feature-enabled]
 
@@ -920,6 +920,11 @@
 # operations testing. (integer value)
 #large_ops_number = 0
 
+# DHCP client used by images to renew DCHP lease. If left empty,
+# update operation will be skipped. Supported clients: "udhcpc",
+# "dhclient" (string value)
+#dhcp_client = udhcpc
+
 
 [service_available]
 
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 3bdcfd6..425ce13 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -37,8 +37,7 @@
             hypervisor='common', os='linux', architecture='x86_64',
             version='7.0', url='xxx://xxxx/xxx/xxx',
             md5hash='add6bb58e139be103324d04d82d8f545')
-        resp, body = self.client.create_agent(**params)
-        self.assertEqual(200, resp.status)
+        body = self.client.create_agent(**params)
         self.agent_id = body['agent_id']
 
     def tearDown(self):
@@ -67,8 +66,7 @@
             hypervisor='kvm', os='win', architecture='x86',
             version='7.0', url='xxx://xxxx/xxx/xxx',
             md5hash='add6bb58e139be103324d04d82d8f545')
-        resp, body = self.client.create_agent(**params)
-        self.assertEqual(200, resp.status)
+        body = self.client.create_agent(**params)
         self.addCleanup(self.client.delete_agent, body['agent_id'])
         for expected_item, value in params.items():
             self.assertEqual(value, body[expected_item])
@@ -79,27 +77,23 @@
         params = self._param_helper(
             version='8.0', url='xxx://xxxx/xxx/xxx2',
             md5hash='add6bb58e139be103324d04d82d8f547')
-        resp, body = self.client.update_agent(self.agent_id, **params)
-        self.assertEqual(200, resp.status)
+        body = self.client.update_agent(self.agent_id, **params)
         for expected_item, value in params.items():
             self.assertEqual(value, body[expected_item])
 
     @test.attr(type='gate')
     def test_delete_agent(self):
         # Delete an agent.
-        resp, _ = self.client.delete_agent(self.agent_id)
-        self.assertEqual(200, resp.status)
+        self.client.delete_agent(self.agent_id)
 
         # Verify the list doesn't contain the deleted agent.
-        resp, agents = self.client.list_agents()
-        self.assertEqual(200, resp.status)
+        agents = self.client.list_agents()
         self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
 
     @test.attr(type='gate')
     def test_list_agents(self):
         # List all agents.
-        resp, agents = self.client.list_agents()
-        self.assertEqual(200, resp.status)
+        agents = self.client.list_agents()
         self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
         self.assertIn(self.agent_id, map(lambda x: x['agent_id'], agents))
 
@@ -110,14 +104,12 @@
             hypervisor='xen', os='linux', architecture='x86',
             version='7.0', url='xxx://xxxx/xxx/xxx1',
             md5hash='add6bb58e139be103324d04d82d8f546')
-        resp, agent_xen = self.client.create_agent(**params)
-        self.assertEqual(200, resp.status)
+        agent_xen = self.client.create_agent(**params)
         self.addCleanup(self.client.delete_agent, agent_xen['agent_id'])
 
         agent_id_xen = agent_xen['agent_id']
         params_filter = {'hypervisor': agent_xen['hypervisor']}
-        resp, agents = self.client.list_agents(params_filter)
-        self.assertEqual(200, resp.status)
+        agents = self.client.list_agents(params_filter)
         self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
         self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
         self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 7c2e604..a866ede 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -35,7 +35,7 @@
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
 
-        resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+        hosts_all = cls.os_adm.hosts_client.list_hosts()
         hosts = map(lambda x: x['host_name'],
                     filter(lambda y: y['service'] == 'compute', hosts_all))
         cls.host = hosts[0]
@@ -52,14 +52,12 @@
     def test_aggregate_create_delete(self):
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self._try_delete_aggregate, aggregate['id'])
-        self.assertEqual(200, resp.status)
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertIsNone(aggregate['availability_zone'])
 
-        resp, _ = self.client.delete_aggregate(aggregate['id'])
-        self.assertEqual(200, resp.status)
+        self.client.delete_aggregate(aggregate['id'])
         self.client.wait_for_resource_deletion(aggregate['id'])
 
     @test.attr(type='gate')
@@ -67,26 +65,23 @@
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         az_name = data_utils.rand_name(self.az_name_prefix)
-        resp, aggregate = self.client.create_aggregate(
+        aggregate = self.client.create_aggregate(
             name=aggregate_name, availability_zone=az_name)
         self.addCleanup(self._try_delete_aggregate, aggregate['id'])
-        self.assertEqual(200, resp.status)
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertEqual(az_name, aggregate['availability_zone'])
 
-        resp, _ = self.client.delete_aggregate(aggregate['id'])
-        self.assertEqual(200, resp.status)
+        self.client.delete_aggregate(aggregate['id'])
         self.client.wait_for_resource_deletion(aggregate['id'])
 
     @test.attr(type='gate')
     def test_aggregate_create_verify_entry_in_list(self):
         # Create an aggregate and ensure it is listed.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        resp, aggregates = self.client.list_aggregates()
-        self.assertEqual(200, resp.status)
+        aggregates = self.client.list_aggregates()
         self.assertIn((aggregate['id'], aggregate['availability_zone']),
                       map(lambda x: (x['id'], x['availability_zone']),
                           aggregates))
@@ -95,11 +90,10 @@
     def test_aggregate_create_update_metadata_get_details(self):
         # Create an aggregate and ensure its details are returned.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        resp, body = self.client.get_aggregate(aggregate['id'])
-        self.assertEqual(200, resp.status)
+        body = self.client.get_aggregate(aggregate['id'])
         self.assertEqual(aggregate['name'], body['name'])
         self.assertEqual(aggregate['availability_zone'],
                          body['availability_zone'])
@@ -107,13 +101,11 @@
 
         # set the metadata of the aggregate
         meta = {"key": "value"}
-        resp, body = self.client.set_metadata(aggregate['id'], meta)
-        self.assertEqual(200, resp.status)
+        body = self.client.set_metadata(aggregate['id'], meta)
         self.assertEqual(meta, body["metadata"])
 
         # verify the metadata has been set
-        resp, body = self.client.get_aggregate(aggregate['id'])
-        self.assertEqual(200, resp.status)
+        body = self.client.get_aggregate(aggregate['id'])
         self.assertEqual(meta, body["metadata"])
 
     @test.attr(type='gate')
@@ -121,11 +113,10 @@
         # Update an aggregate and ensure properties are updated correctly
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         az_name = data_utils.rand_name(self.az_name_prefix)
-        resp, aggregate = self.client.create_aggregate(
+        aggregate = self.client.create_aggregate(
             name=aggregate_name, availability_zone=az_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        self.assertEqual(200, resp.status)
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertEqual(az_name, aggregate['availability_zone'])
         self.assertIsNotNone(aggregate['id'])
@@ -134,15 +125,13 @@
         new_aggregate_name = aggregate_name + '_new'
         new_az_name = az_name + '_new'
 
-        resp, resp_aggregate = self.client.update_aggregate(aggregate_id,
-                                                            new_aggregate_name,
-                                                            new_az_name)
-        self.assertEqual(200, resp.status)
+        resp_aggregate = self.client.update_aggregate(aggregate_id,
+                                                      new_aggregate_name,
+                                                      new_az_name)
         self.assertEqual(new_aggregate_name, resp_aggregate['name'])
         self.assertEqual(new_az_name, resp_aggregate['availability_zone'])
 
-        resp, aggregates = self.client.list_aggregates()
-        self.assertEqual(200, resp.status)
+        aggregates = self.client.list_aggregates()
         self.assertIn((aggregate_id, new_aggregate_name, new_az_name),
                       map(lambda x:
                           (x['id'], x['name'], x['availability_zone']),
@@ -153,18 +142,16 @@
         # Add an host to the given aggregate and remove.
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        resp, body = self.client.add_host(aggregate['id'], self.host)
-        self.assertEqual(200, resp.status)
+        body = self.client.add_host(aggregate['id'], self.host)
         self.assertEqual(aggregate_name, body['name'])
         self.assertEqual(aggregate['availability_zone'],
                          body['availability_zone'])
         self.assertIn(self.host, body['hosts'])
 
-        resp, body = self.client.remove_host(aggregate['id'], self.host)
-        self.assertEqual(200, resp.status)
+        body = self.client.remove_host(aggregate['id'], self.host)
         self.assertEqual(aggregate_name, body['name'])
         self.assertEqual(aggregate['availability_zone'],
                          body['availability_zone'])
@@ -175,12 +162,12 @@
         # Add an host to the given aggregate and list.
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
         self.client.add_host(aggregate['id'], self.host)
         self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
 
-        resp, aggregates = self.client.list_aggregates()
+        aggregates = self.client.list_aggregates()
         aggs = filter(lambda x: x['id'] == aggregate['id'], aggregates)
         self.assertEqual(1, len(aggs))
         agg = aggs[0]
@@ -193,12 +180,12 @@
         # Add an host to the given aggregate and get details.
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
         self.client.add_host(aggregate['id'], self.host)
         self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
 
-        resp, body = self.client.get_aggregate(aggregate['id'])
+        body = self.client.get_aggregate(aggregate['id'])
         self.assertEqual(aggregate_name, body['name'])
         self.assertIsNone(body['availability_zone'])
         self.assertIn(self.host, body['hosts'])
@@ -209,7 +196,7 @@
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         az_name = data_utils.rand_name(self.az_name_prefix)
-        resp, aggregate = self.client.create_aggregate(
+        aggregate = self.client.create_aggregate(
             name=aggregate_name, availability_zone=az_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
         self.client.add_host(aggregate['id'], self.host)
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 219d12e..a450e5d 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -34,7 +34,7 @@
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
 
-        resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+        hosts_all = cls.os_adm.hosts_client.list_hosts()
         hosts = map(lambda x: x['host_name'],
                     filter(lambda y: y['service'] == 'compute', hosts_all))
         cls.host = hosts[0]
@@ -66,8 +66,7 @@
     def test_aggregate_create_with_existent_aggregate_name(self):
         # creating an aggregate with existent aggregate name is forbidden
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.Conflict,
@@ -78,8 +77,7 @@
     def test_aggregate_delete_as_user(self):
         # Regular user is not allowed to delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.Unauthorized,
@@ -96,8 +94,7 @@
     def test_aggregate_get_details_as_user(self):
         # Regular user is not allowed to get aggregate details.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.Unauthorized,
@@ -119,7 +116,7 @@
     @test.attr(type=['negative', 'gate'])
     def test_aggregate_add_non_exist_host(self):
         # Adding a non-exist host to an aggregate should raise exceptions.
-        resp, hosts_all = self.os_adm.hosts_client.list_hosts()
+        hosts_all = self.os_adm.hosts_client.list_hosts()
         hosts = map(lambda x: x['host_name'], hosts_all)
         while True:
             non_exist_host = data_utils.rand_name('nonexist_host_')
@@ -127,7 +124,7 @@
                 break
 
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.NotFound, self.client.add_host,
@@ -137,8 +134,7 @@
     def test_aggregate_add_host_as_user(self):
         # Regular user is not allowed to add a host to an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.Unauthorized,
@@ -149,12 +145,10 @@
     def test_aggregate_add_existent_host(self):
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        resp, body = self.client.add_host(aggregate['id'], self.host)
-        self.assertEqual(200, resp.status)
+        self.client.add_host(aggregate['id'], self.host)
         self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
 
         self.assertRaises(exceptions.Conflict, self.client.add_host,
@@ -165,11 +159,9 @@
         # Regular user is not allowed to remove a host from an aggregate.
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-        resp, body = self.client.add_host(aggregate['id'], self.host)
-        self.assertEqual(200, resp.status)
+        self.client.add_host(aggregate['id'], self.host)
         self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
 
         self.assertRaises(exceptions.Unauthorized,
@@ -180,8 +172,7 @@
     def test_aggregate_remove_nonexistent_host(self):
         non_exist_host = data_utils.rand_name('nonexist_host_')
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(name=aggregate_name)
-        self.assertEqual(200, resp.status)
+        aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(exceptions.NotFound, self.client.remove_host,
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 25965fd..b9d47bb 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -30,19 +30,17 @@
 
     @test.attr(type='gate')
     def test_list_hosts(self):
-        resp, hosts = self.client.list_hosts()
-        self.assertEqual(200, resp.status)
+        hosts = self.client.list_hosts()
         self.assertTrue(len(hosts) >= 2, str(hosts))
 
     @test.attr(type='gate')
     def test_list_hosts_with_zone(self):
         self.useFixture(fixtures.LockFixture('availability_zone'))
-        resp, hosts = self.client.list_hosts()
+        hosts = self.client.list_hosts()
         host = hosts[0]
         zone_name = host['zone']
         params = {'zone': zone_name}
-        resp, hosts = self.client.list_hosts(params)
-        self.assertEqual(200, resp.status)
+        hosts = self.client.list_hosts(params)
         self.assertTrue(len(hosts) >= 1)
         self.assertIn(host, hosts)
 
@@ -51,31 +49,27 @@
         # If send the request with a blank zone, the request will be successful
         # and it will return all the hosts list
         params = {'zone': ''}
-        resp, hosts = self.client.list_hosts(params)
+        hosts = self.client.list_hosts(params)
         self.assertNotEqual(0, len(hosts))
-        self.assertEqual(200, resp.status)
 
     @test.attr(type='gate')
     def test_list_hosts_with_nonexistent_zone(self):
         # If send the request with a nonexistent zone, the request will be
         # successful and no hosts will be retured
         params = {'zone': 'xxx'}
-        resp, hosts = self.client.list_hosts(params)
+        hosts = self.client.list_hosts(params)
         self.assertEqual(0, len(hosts))
-        self.assertEqual(200, resp.status)
 
     @test.attr(type='gate')
     def test_show_host_detail(self):
-        resp, hosts = self.client.list_hosts()
-        self.assertEqual(200, resp.status)
+        hosts = self.client.list_hosts()
 
         hosts = [host for host in hosts if host['service'] == 'compute']
         self.assertTrue(len(hosts) >= 1)
 
         for host in hosts:
             hostname = host['host_name']
-            resp, resources = self.client.show_host_detail(hostname)
-            self.assertEqual(200, resp.status)
+            resources = self.client.show_host_detail(hostname)
             self.assertTrue(len(resources) >= 1)
             host_resource = resources[0]['resource']
             self.assertIsNotNone(host_resource)
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 055219f..fc918a3 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -31,8 +31,7 @@
         cls.non_admin_client = cls.os.hosts_client
 
     def _get_host_name(self):
-        resp, hosts = self.client.list_hosts()
-        self.assertEqual(200, resp.status)
+        hosts = self.client.list_hosts()
         self.assertTrue(len(hosts) >= 1)
         hostname = hosts[0]['host_name']
         return hostname
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index de3debb..fbfef87 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -30,8 +30,7 @@
 
     def _list_hypervisors(self):
         # List of hypervisors
-        resp, hypers = self.client.get_hypervisor_list()
-        self.assertEqual(200, resp.status)
+        hypers = self.client.get_hypervisor_list()
         return hypers
 
     def assertHypervisors(self, hypers):
@@ -46,8 +45,7 @@
     @test.attr(type='gate')
     def test_get_hypervisor_list_details(self):
         # Display the details of the all hypervisor
-        resp, hypers = self.client.get_hypervisor_list_details()
-        self.assertEqual(200, resp.status)
+        hypers = self.client.get_hypervisor_list_details()
         self.assertHypervisors(hypers)
 
     @test.attr(type='gate')
@@ -56,9 +54,7 @@
         hypers = self._list_hypervisors()
         self.assertHypervisors(hypers)
 
-        resp, details = (self.client.
-                         get_hypervisor_show_details(hypers[0]['id']))
-        self.assertEqual(200, resp.status)
+        details = self.client.get_hypervisor_show_details(hypers[0]['id'])
         self.assertTrue(len(details) > 0)
         self.assertEqual(details['hypervisor_hostname'],
                          hypers[0]['hypervisor_hostname'])
@@ -70,15 +66,13 @@
         self.assertHypervisors(hypers)
 
         hostname = hypers[0]['hypervisor_hostname']
-        resp, hypervisors = self.client.get_hypervisor_servers(hostname)
-        self.assertEqual(200, resp.status)
+        hypervisors = self.client.get_hypervisor_servers(hostname)
         self.assertTrue(len(hypervisors) > 0)
 
     @test.attr(type='gate')
     def test_get_hypervisor_stats(self):
         # Verify the stats of the all hypervisor
-        resp, stats = self.client.get_hypervisor_stats()
-        self.assertEqual(200, resp.status)
+        stats = self.client.get_hypervisor_stats()
         self.assertTrue(len(stats) > 0)
 
     @test.attr(type='gate')
@@ -94,9 +88,7 @@
         ironic_only = True
         hypers_without_ironic = []
         for hyper in hypers:
-            resp, details = (self.client.
-                             get_hypervisor_show_details(hypers[0]['id']))
-            self.assertEqual(200, resp.status)
+            details = self.client.get_hypervisor_show_details(hypers[0]['id'])
             if details['hypervisor_type'] != 'ironic':
                 hypers_without_ironic.append(hyper)
                 ironic_only = False
@@ -110,8 +102,8 @@
             # because hypervisors might be disabled, this loops looking
             # for any good hit.
             try:
-                resp, uptime = self.client.get_hypervisor_uptime(hyper['id'])
-                if (resp.status == 200) and (len(uptime) > 0):
+                uptime = self.client.get_hypervisor_uptime(hyper['id'])
+                if len(uptime) > 0:
                     has_valid_uptime = True
                     break
             except Exception:
@@ -124,7 +116,6 @@
     def test_search_hypervisor(self):
         hypers = self._list_hypervisors()
         self.assertHypervisors(hypers)
-        resp, hypers = self.client.search_hypervisor(
+        hypers = self.client.search_hypervisor(
             hypers[0]['hypervisor_hostname'])
-        self.assertEqual(200, resp.status)
         self.assertHypervisors(hypers)
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index b1f2351..a137a61 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -35,8 +35,7 @@
 
     def _list_hypervisors(self):
         # List of hypervisors
-        resp, hypers = self.client.get_hypervisor_list()
-        self.assertEqual(200, resp.status)
+        hypers = self.client.get_hypervisor_list()
         return hypers
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index e7a39f8..5cf4a31 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -31,29 +31,27 @@
 
     @test.attr(type='gate')
     def test_list_services(self):
-        resp, services = self.client.list_services()
-        self.assertEqual(200, resp.status)
+        services = self.client.list_services()
         self.assertNotEqual(0, len(services))
 
     @test.attr(type='gate')
     def test_get_service_by_service_binary_name(self):
         binary_name = 'nova-compute'
         params = {'binary': binary_name}
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
+        services = self.client.list_services(params)
         self.assertNotEqual(0, len(services))
         for service in services:
             self.assertEqual(binary_name, service['binary'])
 
     @test.attr(type='gate')
     def test_get_service_by_host_name(self):
-        resp, services = self.client.list_services()
+        services = self.client.list_services()
         host_name = services[0]['host']
         services_on_host = [service for service in services if
                             service['host'] == host_name]
         params = {'host': host_name}
 
-        resp, services = self.client.list_services(params)
+        services = self.client.list_services(params)
 
         # we could have a periodic job checkin between the 2 service
         # lookups, so only compare binary lists.
@@ -66,13 +64,12 @@
 
     @test.attr(type='gate')
     def test_get_service_by_service_and_host_name(self):
-        resp, services = self.client.list_services()
+        services = self.client.list_services()
         host_name = services[0]['host']
         binary_name = services[0]['binary']
         params = {'host': host_name, 'binary': binary_name}
 
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
+        services = self.client.list_services(params)
         self.assertEqual(1, len(services))
         self.assertEqual(host_name, services[0]['host'])
         self.assertEqual(binary_name, services[0]['binary'])
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 534afc5..bb19a39 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -37,26 +37,23 @@
     @test.attr(type=['negative', 'gate'])
     def test_get_service_by_invalid_params(self):
         # return all services if send the request with invalid parameter
-        resp, services = self.client.list_services()
+        services = self.client.list_services()
         params = {'xxx': 'nova-compute'}
-        resp, services_xxx = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
+        services_xxx = self.client.list_services(params)
         self.assertEqual(len(services), len(services_xxx))
 
     @test.attr(type=['negative', 'gate'])
     def test_get_service_by_invalid_service_and_valid_host(self):
-        resp, services = self.client.list_services()
+        services = self.client.list_services()
         host_name = services[0]['host']
         params = {'host': host_name, 'binary': 'xxx'}
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
+        services = self.client.list_services(params)
         self.assertEqual(0, len(services))
 
     @test.attr(type=['negative', 'gate'])
     def test_get_service_with_valid_service_and_invalid_host(self):
-        resp, services = self.client.list_services()
+        services = self.client.list_services()
         binary_name = services[0]['binary']
         params = {'host': 'xxx', 'binary': binary_name}
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
+        services = self.client.list_services(params)
         self.assertEqual(0, len(services))
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index cb75d07..e04439f 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -36,7 +36,7 @@
         cls.created_server_ids = []
 
     def _get_compute_hostnames(self):
-        _resp, body = self.admin_hosts_client.list_hosts()
+        body = self.admin_hosts_client.list_hosts()
         return [
             host_record['host_name']
             for host_record in body
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index e70519e..65aeb24 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -15,7 +15,6 @@
 import itertools
 
 import netaddr
-import testtools
 
 from tempest.api.network import base
 from tempest.common import custom_matchers
@@ -571,9 +570,16 @@
                               test_subnet_ids,
                               'Subnet are not in the same network')
 
-    @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
-                          "IPv6 extended attributes for subnets not "
-                          "available")
+
+class NetworksIpV6TestAttrs(NetworksIpV6TestJSON):
+
+    @classmethod
+    def resource_setup(cls):
+        if not CONF.network_feature_enabled.ipv6_subnet_attributes:
+            raise cls.skipException("IPv6 extended attributes for "
+                                    "subnets not available")
+        super(NetworksIpV6TestAttrs, cls).resource_setup()
+
     @test.attr(type='smoke')
     def test_create_delete_subnet_with_v6_attributes_stateful(self):
         self._create_verify_delete_subnet(
@@ -581,20 +587,54 @@
             ipv6_ra_mode='dhcpv6-stateful',
             ipv6_address_mode='dhcpv6-stateful')
 
-    @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
-                          "IPv6 extended attributes for subnets not "
-                          "available")
     @test.attr(type='smoke')
     def test_create_delete_subnet_with_v6_attributes_slaac(self):
         self._create_verify_delete_subnet(
             ipv6_ra_mode='slaac',
             ipv6_address_mode='slaac')
 
-    @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
-                          "IPv6 extended attributes for subnets not "
-                          "available")
     @test.attr(type='smoke')
     def test_create_delete_subnet_with_v6_attributes_stateless(self):
         self._create_verify_delete_subnet(
             ipv6_ra_mode='dhcpv6-stateless',
             ipv6_address_mode='dhcpv6-stateless')
+
+    def _test_delete_subnet_with_ports(self, mode):
+        """Create subnet and delete it with existing ports"""
+        slaac_network = self.create_network()
+        subnet_slaac = self.create_subnet(slaac_network,
+                                          **{'ipv6_ra_mode': mode,
+                                             'ipv6_address_mode': mode})
+        port = self.create_port(slaac_network)
+        self.assertIsNotNone(port['fixed_ips'][0]['ip_address'])
+        self.client.delete_subnet(subnet_slaac['id'])
+        self.subnets.pop()
+        subnets = self.client.list_subnets()
+        subnet_ids = [subnet['id'] for subnet in subnets['subnets']]
+        self.assertNotIn(subnet_slaac['id'], subnet_ids,
+                         "Subnet wasn't deleted")
+        self.assertRaisesRegexp(
+            exceptions.Conflict,
+            "There are one or more ports still in use on the network",
+            self.client.delete_network,
+            slaac_network['id'])
+
+    @test.attr(type='smoke')
+    def test_create_delete_slaac_subnet_with_ports(self):
+        """Test deleting subnet with SLAAC ports
+
+        Create subnet with SLAAC, create ports in network
+        and then you shall be able to delete subnet without port
+        deletion. But you still can not delete the network.
+        """
+        self._test_delete_subnet_with_ports("slaac")
+
+    @test.attr(type='smoke')
+    def test_create_delete_stateless_subnet_with_ports(self):
+        """Test deleting subnet with DHCPv6 stateless ports
+
+        Create subnet with DHCPv6 stateless, create ports in network
+        and then you shall be able to delete subnet without port
+        deletion. But you still can not delete the network.
+        """
+        self._test_delete_subnet_with_ports("dhcpv6-stateless")
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index ee0e4c8..bf85e90 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -17,6 +17,7 @@
 import socket
 
 from tempest.api.network import base
+from tempest.api.network import base_security_groups as sec_base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
@@ -25,7 +26,7 @@
 CONF = config.CONF
 
 
-class PortsTestJSON(base.BaseNetworkTest):
+class PortsTestJSON(sec_base.BaseSecGroupTest):
     _interface = 'json'
 
     """
@@ -102,7 +103,8 @@
         address = self._get_ipaddress_from_tempest_conf()
         allocation_pools = {'allocation_pools': [{'start': str(address + 4),
                                                   'end': str(address + 6)}]}
-        self.create_subnet(network, **allocation_pools)
+        subnet = self.create_subnet(network, **allocation_pools)
+        self.addCleanup(self.client.delete_subnet, subnet['id'])
         body = self.client.create_port(network_id=net_id)
         self.addCleanup(self.client.delete_port, body['port']['id'])
         port = body['port']
@@ -148,8 +150,11 @@
     def test_port_list_filter_by_router_id(self):
         # Create a router
         network = self.create_network()
-        self.create_subnet(network)
+        self.addCleanup(self.client.delete_network, network['id'])
+        subnet = self.create_subnet(network)
+        self.addCleanup(self.client.delete_subnet, subnet['id'])
         router = self.create_router(data_utils.rand_name('router-'))
+        self.addCleanup(self.client.delete_router, router['id'])
         port = self.client.create_port(network_id=network['id'])
         # Add router interface to port created above
         self.client.add_router_interface_with_port_id(
@@ -175,31 +180,41 @@
             self.assertEqual(sorted(fields), sorted(port.keys()))
 
     @test.attr(type='smoke')
-    def test_update_port_with_second_ip(self):
+    def test_create_update_port_with_second_ip(self):
         # Create a network with two subnets
         network = self.create_network()
+        self.addCleanup(self.client.delete_network, network['id'])
         subnet_1 = self.create_subnet(network)
+        self.addCleanup(self.client.delete_subnet, subnet_1['id'])
         subnet_2 = self.create_subnet(network)
+        self.addCleanup(self.client.delete_subnet, subnet_2['id'])
         fixed_ip_1 = [{'subnet_id': subnet_1['id']}]
         fixed_ip_2 = [{'subnet_id': subnet_2['id']}]
 
-        # Create a port with a single IP address from first subnet
-        port = self.create_port(network,
-                                fixed_ips=fixed_ip_1)
-        self.assertEqual(1, len(port['fixed_ips']))
-
-        # Update the port with a second IP address from second subnet
         fixed_ips = fixed_ip_1 + fixed_ip_2
-        port = self.update_port(port, fixed_ips=fixed_ips)
+
+        # Create a port with multiple IP addresses
+        port = self.create_port(network,
+                                fixed_ips=fixed_ips)
+        self.addCleanup(self.client.delete_port, port['id'])
         self.assertEqual(2, len(port['fixed_ips']))
+        check_fixed_ips = [subnet_1['id'], subnet_2['id']]
+        for item in port['fixed_ips']:
+            self.assertIn(item['subnet_id'], check_fixed_ips)
 
         # Update the port to return to a single IP address
         port = self.update_port(port, fixed_ips=fixed_ip_1)
         self.assertEqual(1, len(port['fixed_ips']))
 
+        # Update the port with a second IP address from second subnet
+        port = self.update_port(port, fixed_ips=fixed_ips)
+        self.assertEqual(2, len(port['fixed_ips']))
+
     def _update_port_with_security_groups(self, security_groups_names):
-        post_body = {"network_id": self.network['id']}
-        self.create_subnet(self.network)
+        subnet_1 = self.create_subnet(self.network)
+        self.addCleanup(self.client.delete_subnet, subnet_1['id'])
+        fixed_ip_1 = [{'subnet_id': subnet_1['id']}]
+
         security_groups_list = list()
         for name in security_groups_names:
             group_create_body = self.client.create_security_group(
@@ -209,24 +224,48 @@
             security_groups_list.append(group_create_body['security_group']
                                         ['id'])
         # Create a port
+        sec_grp_name = data_utils.rand_name('secgroup')
+        security_group = self.client.create_security_group(name=sec_grp_name)
+        self.addCleanup(self.client.delete_security_group,
+                        security_group['security_group']['id'])
+        post_body = {
+            "name": data_utils.rand_name('port-'),
+            "security_groups": [security_group['security_group']['id']],
+            "network_id": self.network['id'],
+            "admin_state_up": True,
+            "fixed_ips": fixed_ip_1}
         body = self.client.create_port(**post_body)
         self.addCleanup(self.client.delete_port, body['port']['id'])
         port = body['port']
+
         # Update the port with security groups
-        update_body = {"security_groups": security_groups_list}
+        subnet_2 = self.create_subnet(self.network)
+        fixed_ip_2 = [{'subnet_id': subnet_2['id']}]
+        update_body = {"name": data_utils.rand_name('port-'),
+                       "admin_state_up": False,
+                       "fixed_ips": fixed_ip_2,
+                       "security_groups": security_groups_list}
         body = self.client.update_port(port['id'], **update_body)
-        # Verify the security groups updated to port
         port_show = body['port']
+        # Verify the security groups and other attributes updated to port
+        exclude_keys = set(port_show).symmetric_difference(update_body)
+        exclude_keys.add('fixed_ips')
+        exclude_keys.add('security_groups')
+        self.assertThat(port_show, custom_matchers.MatchesDictExceptForKeys(
+                        update_body, exclude_keys))
+        self.assertEqual(fixed_ip_2[0]['subnet_id'],
+                         port_show['fixed_ips'][0]['subnet_id'])
+
         for security_group in security_groups_list:
             self.assertIn(security_group, port_show['security_groups'])
 
     @test.attr(type='smoke')
-    def test_update_port_with_security_group(self):
+    def test_update_port_with_security_group_and_extra_attributes(self):
         self._update_port_with_security_groups(
             [data_utils.rand_name('secgroup')])
 
     @test.attr(type='smoke')
-    def test_update_port_with_two_security_groups(self):
+    def test_update_port_with_two_security_groups_and_extra_attributes(self):
         self._update_port_with_security_groups(
             [data_utils.rand_name('secgroup'),
              data_utils.rand_name('secgroup')])
@@ -251,23 +290,14 @@
     @test.attr(type='smoke')
     def test_create_port_with_no_securitygroups(self):
         network = self.create_network()
-        self.create_subnet(network)
+        self.addCleanup(self.client.delete_network, network['id'])
+        subnet = self.create_subnet(network)
+        self.addCleanup(self.client.delete_subnet, subnet['id'])
         port = self.create_port(network, security_groups=[])
+        self.addCleanup(self.client.delete_port, port['id'])
         self.assertIsNotNone(port['security_groups'])
         self.assertEmpty(port['security_groups'])
 
-    @test.attr(type='smoke')
-    def test_update_port_with_no_securitygroups(self):
-        network = self.create_network()
-        self.create_subnet(network)
-        port = self.create_port(network)
-        # Verify that port is created with default security group
-        self.assertIsNotNone(port['security_groups'])
-        self.assertNotEmpty(port['security_groups'])
-        updated_port = self.update_port(port, security_groups=[])
-        self.assertIsNotNone(updated_port['security_groups'])
-        self.assertEmpty(updated_port['security_groups'])
-
 
 class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
     _interface = 'json'
diff --git a/tempest/clients.py b/tempest/clients.py
index 8d59742..de03f1d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -139,9 +139,9 @@
         # super cares for credentials validation
         super(Manager, self).__init__(credentials=credentials)
 
-        self._set_compute_clients(self.interface)
-        self._set_identity_clients(self.interface)
-        self._set_volume_clients(self.interface)
+        self._set_compute_clients()
+        self._set_identity_clients()
+        self._set_volume_clients()
 
         self.baremetal_client = BaremetalClientJSON(self.auth_provider)
         self.network_client = NetworkClientJSON(self.auth_provider)
@@ -176,17 +176,12 @@
         self.data_processing_client = DataProcessingClient(
             self.auth_provider)
 
-    def _set_compute_clients(self, type):
-        self._set_compute_json_clients()
-
-        # Common compute clients
+    def _set_compute_clients(self):
         self.agents_client = AgentsClientJSON(self.auth_provider)
         self.networks_client = NetworksClientJSON(self.auth_provider)
         self.migrations_client = MigrationsClientJSON(self.auth_provider)
         self.security_group_default_rules_client = (
             SecurityGroupDefaultRulesClientJSON(self.auth_provider))
-
-    def _set_compute_json_clients(self):
         self.certificates_client = CertificatesClientJSON(self.auth_provider)
         self.servers_client = ServersClientJSON(self.auth_provider)
         self.limits_client = LimitsClientJSON(self.auth_provider)
@@ -213,10 +208,7 @@
         self.instance_usages_audit_log_client = \
             InstanceUsagesAuditLogClientJSON(self.auth_provider)
 
-    def _set_identity_clients(self, type):
-        self._set_identity_json_clients()
-
-    def _set_identity_json_clients(self):
+    def _set_identity_clients(self):
         self.identity_client = IdentityClientJSON(self.auth_provider)
         self.identity_v3_client = IdentityV3ClientJSON(self.auth_provider)
         self.endpoints_client = EndPointClientJSON(self.auth_provider)
@@ -228,20 +220,12 @@
             self.token_v3_client = V3TokenClientJSON()
         self.credentials_client = CredentialsClientJSON(self.auth_provider)
 
-    def _set_volume_clients(self, type):
-        self._set_volume_json_clients()
-        # Common volume clients
-        # NOTE : As XML clients are not implemented for Qos-specs.
-        # So, setting the qos_client here. Once client are implemented,
-        # qos_client would be moved to its respective if/else.
-        # Bug : 1312553
+    def _set_volume_clients(self):
         self.volume_qos_client = QosSpecsClientJSON(self.auth_provider)
         self.volume_qos_v2_client = QosSpecsV2ClientJSON(
             self.auth_provider)
         self.volume_services_v2_client = VolumesServicesV2ClientJSON(
             self.auth_provider)
-
-    def _set_volume_json_clients(self):
         self.backups_client = BackupsClientJSON(self.auth_provider)
         self.backups_v2_client = BackupsClientV2JSON(self.auth_provider)
         self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index e7590b7..a663931 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -124,7 +124,7 @@
             self._assign_user_role(tenant, user, swift_operator_role)
         if admin:
             self._assign_user_role(tenant, user, CONF.identity.admin_role)
-        for role in CONF.identity.tempest_roles:
+        for role in CONF.auth.tempest_roles:
             self._assign_user_role(tenant, user, role)
         return self._get_credentials(user, tenant)
 
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index d8bfef8..6e61c55 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -97,6 +97,10 @@
         cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
         return self.exec_command(cmd)
 
+    def get_nic_name(self, address):
+        cmd = "/bin/ip -o addr | awk '/%s/ {print $2}'" % address
+        return self.exec_command(cmd)
+
     def get_ip_list(self):
         cmd = "/bin/ip address"
         return self.exec_command(cmd)
@@ -116,3 +120,47 @@
         # Get pid(s) of a process/program
         cmd = "ps -ef | grep %s | grep -v 'grep' | awk {'print $1'}" % pr_name
         return self.exec_command(cmd).split('\n')
+
+    def get_dns_servers(self):
+        cmd = 'cat /etc/resolv.conf'
+        resolve_file = self.exec_command(cmd).strip().split('\n')
+        entries = (l.split() for l in resolve_file)
+        dns_servers = [l[1] for l in entries
+                       if len(l) and l[0] == 'nameserver']
+        return dns_servers
+
+    def send_signal(self, pid, signum):
+        cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig=signum)
+        return self.exec_command(cmd)
+
+    def _renew_lease_udhcpc(self, fixed_ip=None):
+        """Renews DHCP lease via udhcpc client. """
+        file_path = '/var/run/udhcpc.'
+        nic_name = self.get_nic_name(fixed_ip)
+        nic_name = nic_name.strip().lower()
+        pid = self.exec_command('cat {path}{nic}.pid'.
+                                format(path=file_path, nic=nic_name))
+        pid = pid.strip()
+        self.send_signal(pid, 'USR1')
+
+    def _renew_lease_dhclient(self, fixed_ip=None):
+        """Renews DHCP lease via dhclient client. """
+        cmd = "sudo /sbin/dhclient -r && /sbin/dhclient"
+        self.exec_command(cmd)
+
+    def renew_lease(self, fixed_ip=None):
+        """Wrapper method for renewing DHCP lease via given client
+
+        Supporting:
+        * udhcpc
+        * dhclient
+        """
+        # TODO(yfried): add support for dhcpcd
+        suported_clients = ['udhcpc', 'dhclient']
+        dhcp_client = CONF.scenario.dhcp_client
+        if dhcp_client not in suported_clients:
+            raise exceptions.InvalidConfiguration('%s DHCP client unsupported'
+                                                  % dhcp_client)
+        if dhcp_client == 'udhcpc' and not fixed_ip:
+            raise ValueError("need to set 'fixed_ip' for udhcpc client")
+        return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
\ No newline at end of file
diff --git a/tempest/config.py b/tempest/config.py
index 4858fda..dd693e5 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -59,6 +59,9 @@
                      "It requires at least `2 * CONC` distinct accounts "
                      "configured in `test_accounts_file`, with CONC == the "
                      "number of concurrent test processes."),
+    cfg.ListOpt('tempest_roles',
+                help="Roles to assign to all users created by tempest",
+                default=[])
 ]
 
 identity_group = cfg.OptGroup(name='identity',
@@ -131,9 +134,6 @@
     cfg.StrOpt('admin_domain_name',
                help="Admin domain name for authentication (Keystone V3)."
                     "The same domain applies to user and project"),
-    cfg.ListOpt('tempest_roles',
-                help="Roles to assign to all users created by tempest",
-                default=[])
 ]
 
 identity_feature_group = cfg.OptGroup(name='identity-feature-enabled',
@@ -860,7 +860,14 @@
         'large_ops_number',
         default=0,
         help="specifies how many resources to request at once. Used "
-        "for large operations testing.")
+        "for large operations testing."),
+    # TODO(yfried): add support for dhcpcd
+    cfg.StrOpt('dhcp_client',
+               default='udhcpc',
+               choices=["udhcpc", "dhclient"],
+               help='DHCP client used by images to renew DCHP lease. '
+                    'If left empty, update operation will be skipped. '
+                    'Supported clients: "udhcpc", "dhclient"')
 ]
 
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 220a7e7..1fdd26a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1012,12 +1012,16 @@
         router.update(admin_state_up=admin_state_up)
         self.assertEqual(admin_state_up, router.admin_state_up)
 
-    def create_networks(self, client=None, tenant_id=None):
+    def create_networks(self, client=None, tenant_id=None,
+                        dns_nameservers=None):
         """Create a network with a subnet connected to a router.
 
         The baremetal driver is a special case since all nodes are
         on the same shared network.
 
+        :param client: network client to create resources with.
+        :param tenant_id: id of tenant to create resources in.
+        :param dns_nameservers: list of dns servers to send to subnet.
         :returns: network, subnet, router
         """
         if CONF.baremetal.driver_enabled:
@@ -1033,7 +1037,12 @@
         else:
             network = self._create_network(client=client, tenant_id=tenant_id)
             router = self._get_router(client=client, tenant_id=tenant_id)
-            subnet = self._create_subnet(network=network, client=client)
+
+            subnet_kwargs = dict(network=network, client=client)
+            # use explicit check because empty list is a valid option
+            if dns_nameservers is not None:
+                subnet_kwargs['dns_nameservers'] = dns_nameservers
+            subnet = self._create_subnet(**subnet_kwargs)
             subnet.add_to_router(router.id)
         return network, subnet, router
 
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 75769ce..469ac4a 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -43,7 +43,7 @@
         return cls.admin_credentials()
 
     def _create_aggregate(self, **kwargs):
-        _, aggregate = self.aggregates_client.create_aggregate(**kwargs)
+        aggregate = self.aggregates_client.create_aggregate(**kwargs)
         self.addCleanup(self._delete_aggregate, aggregate)
         aggregate_name = kwargs['name']
         availability_zone = kwargs['availability_zone']
@@ -55,23 +55,23 @@
         self.aggregates_client.delete_aggregate(aggregate['id'])
 
     def _get_host_name(self):
-        _, hosts = self.hosts_client.list_hosts()
+        hosts = self.hosts_client.list_hosts()
         self.assertTrue(len(hosts) >= 1)
         computes = [x for x in hosts if x['service'] == 'compute']
         return computes[0]['host_name']
 
     def _add_host(self, aggregate_id, host):
-        _, aggregate = self.aggregates_client.add_host(aggregate_id, host)
+        aggregate = self.aggregates_client.add_host(aggregate_id, host)
         self.addCleanup(self._remove_host, aggregate['id'], host)
         self.assertIn(host, aggregate['hosts'])
 
     def _remove_host(self, aggregate_id, host):
-        _, aggregate = self.aggregates_client.remove_host(aggregate_id, host)
+        aggregate = self.aggregates_client.remove_host(aggregate_id, host)
         self.assertNotIn(host, aggregate['hosts'])
 
     def _check_aggregate_details(self, aggregate, aggregate_name, azone,
                                  hosts, metadata):
-        _, aggregate = self.aggregates_client.get_aggregate(aggregate['id'])
+        aggregate = self.aggregates_client.get_aggregate(aggregate['id'])
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertEqual(azone, aggregate['availability_zone'])
         self.assertEqual(hosts, aggregate['hosts'])
@@ -81,15 +81,15 @@
                              aggregate['metadata'][meta_key])
 
     def _set_aggregate_metadata(self, aggregate, meta):
-        _, aggregate = self.aggregates_client.set_metadata(aggregate['id'],
-                                                           meta)
+        aggregate = self.aggregates_client.set_metadata(aggregate['id'],
+                                                        meta)
 
         for key, value in meta.items():
             self.assertEqual(meta[key], aggregate['metadata'][key])
 
     def _update_aggregate(self, aggregate, aggregate_name,
                           availability_zone):
-        _, aggregate = self.aggregates_client.update_aggregate(
+        aggregate = self.aggregates_client.update_aggregate(
             aggregate['id'], name=aggregate_name,
             availability_zone=availability_zone)
         self.assertEqual(aggregate['name'], aggregate_name)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 30c3b9d..2cfec14 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -100,10 +100,10 @@
         self.keypairs = {}
         self.servers = []
 
-    def _setup_network_and_servers(self):
+    def _setup_network_and_servers(self, **kwargs):
         self.security_group = \
             self._create_security_group(tenant_id=self.tenant_id)
-        self.network, self.subnet, self.router = self.create_networks()
+        self.network, self.subnet, self.router = self.create_networks(**kwargs)
         self.check_networks()
 
         name = data_utils.rand_name('server-smoke')
@@ -425,3 +425,62 @@
         self.check_public_network_connectivity(
             should_connect=True, msg="after updating "
             "admin_state_up of router to True")
+
+    def _check_dns_server(self, ssh_client, dns_servers):
+        servers = ssh_client.get_dns_servers()
+        self.assertEqual(set(dns_servers), set(servers),
+                         'Looking for servers: {trgt_serv}. '
+                         'Retrieved DNS nameservers: {act_serv} '
+                         'From host: {host}.'
+                         .format(host=ssh_client.ssh_client.host,
+                                 act_serv=servers,
+                                 trgt_serv=dns_servers))
+
+    @testtools.skipUnless(CONF.scenario.dhcp_client,
+                          "DHCP client is not available.")
+    @test.attr(type='smoke')
+    @test.services('compute', 'network')
+    def test_subnet_details(self):
+        """Tests that subnet's extra configuration details are affecting
+        the VMs
+
+         NOTE: Neutron subnets push data to servers via dhcp-agent, so any
+         update in subnet requires server to actively renew its DHCP lease.
+
+         1. Configure subnet with dns nameserver
+         2. retrieve the VM's configured dns and verify it matches the one
+         configured for the subnet.
+         3. update subnet's dns
+         4. retrieve the VM's configured dns and verify it matches the new one
+         configured for the subnet.
+
+         TODO(yfried): add host_routes
+
+         any resolution check would be testing either:
+            * l3 forwarding (tested in test_network_basic_ops)
+            * Name resolution of an external DNS nameserver - out of scope for
+            Tempest
+        """
+        # this test check only updates (no actual resolution) so using
+        # arbitrary ip addresses as nameservers, instead of parsing CONF
+        initial_dns_server = '1.2.3.4'
+        alt_dns_server = '9.8.7.6'
+        self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
+        self.check_public_network_connectivity(should_connect=True)
+
+        floating_ip, server = self.floating_ip_tuple
+        ip_address = floating_ip.floating_ip_address
+        private_key = self._get_server_key(server)
+        ssh_client = self._ssh_to_server(ip_address, private_key)
+
+        self._check_dns_server(ssh_client, [initial_dns_server])
+
+        self.subnet.update(dns_nameservers=[alt_dns_server])
+        # asserts that Neutron DB has updated the nameservers
+        self.assertEqual([alt_dns_server], self.subnet.dns_nameservers,
+                         "Failed to update subnet's nameservers")
+
+        # server needs to renew its dhcp lease in order to get the new dns
+        # definitions from subnet
+        ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'])
+        self._check_dns_server(ssh_client, [alt_dns_server])
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index eacd367..95d7880 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -17,6 +17,7 @@
 
 from tempest.api_schema.response.compute import agents as common_schema
 from tempest.api_schema.response.compute.v2 import agents as schema
+from tempest.common import service_client
 from tempest.services.compute.json import base
 
 
@@ -33,7 +34,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.validate_response(common_schema.list_agents, resp, body)
-        return resp, body['agents']
+        return service_client.ResponseBodyList(resp, body['agents'])
 
     def create_agent(self, **kwargs):
         """Create an agent build."""
@@ -41,16 +42,16 @@
         resp, body = self.post('os-agents', post_body)
         body = json.loads(body)
         self.validate_response(schema.create_agent, resp, body)
-        return resp, body['agent']
+        return service_client.ResponseBody(resp, body['agent'])
 
     def delete_agent(self, agent_id):
         """Delete an existing agent build."""
         resp, body = self.delete("os-agents/%s" % str(agent_id))
         self.validate_response(schema.delete_agent, resp, body)
-        return resp, body
+        return service_client.ResponseBody(resp, body)
 
     def update_agent(self, agent_id, **kwargs):
         """Update an agent build."""
         put_body = json.dumps({'para': kwargs})
         resp, body = self.put('os-agents/%s' % str(agent_id), put_body)
-        return resp, self._parse_resp(body)
+        return service_client.ResponseBody(resp, self._parse_resp(body))
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 1539259..47dd401 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -17,6 +17,7 @@
 
 from tempest.api_schema.response.compute import aggregates as schema
 from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
+from tempest.common import service_client
 from tempest import exceptions
 from tempest.services.compute.json import base
 
@@ -28,14 +29,14 @@
         resp, body = self.get("os-aggregates")
         body = json.loads(body)
         self.validate_response(schema.list_aggregates, resp, body)
-        return resp, body['aggregates']
+        return service_client.ResponseBodyList(resp, body['aggregates'])
 
     def get_aggregate(self, aggregate_id):
         """Get details of the given aggregate."""
         resp, body = self.get("os-aggregates/%s" % str(aggregate_id))
         body = json.loads(body)
         self.validate_response(schema.get_aggregate, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
 
     def create_aggregate(self, **kwargs):
         """Creates a new aggregate."""
@@ -44,7 +45,7 @@
 
         body = json.loads(body)
         self.validate_response(v2_schema.create_aggregate, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
 
     def update_aggregate(self, aggregate_id, name, availability_zone=None):
         """Update a aggregate."""
@@ -57,13 +58,13 @@
 
         body = json.loads(body)
         self.validate_response(schema.update_aggregate, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
 
     def delete_aggregate(self, aggregate_id):
         """Deletes the given aggregate."""
         resp, body = self.delete("os-aggregates/%s" % str(aggregate_id))
         self.validate_response(v2_schema.delete_aggregate, resp, body)
-        return resp, body
+        return service_client.ResponseBody(resp, body)
 
     def is_resource_deleted(self, id):
         try:
@@ -87,7 +88,7 @@
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.aggregate_add_remove_host, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
 
     def remove_host(self, aggregate_id, host):
         """Removes a host from the given aggregate."""
@@ -99,7 +100,7 @@
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.aggregate_add_remove_host, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
 
     def set_metadata(self, aggregate_id, meta):
         """Replaces the aggregate's existing metadata with new metadata."""
@@ -111,4 +112,4 @@
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.aggregate_set_metadata, resp, body)
-        return resp, body['aggregate']
+        return service_client.ResponseBody(resp, body['aggregate'])
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 5d306f9..f4e1f12 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -17,6 +17,7 @@
 
 from tempest.api_schema.response.compute import hosts as schema
 from tempest.api_schema.response.compute.v2 import hosts as v2_schema
+from tempest.common import service_client
 from tempest.services.compute.json import base
 
 
@@ -32,7 +33,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.validate_response(schema.list_hosts, resp, body)
-        return resp, body['hosts']
+        return service_client.ResponseBodyList(resp, body['hosts'])
 
     def show_host_detail(self, hostname):
         """Show detail information for the host."""
@@ -40,7 +41,7 @@
         resp, body = self.get("os-hosts/%s" % str(hostname))
         body = json.loads(body)
         self.validate_response(schema.show_host_detail, resp, body)
-        return resp, body['host']
+        return service_client.ResponseBodyList(resp, body['host'])
 
     def update_host(self, hostname, **kwargs):
         """Update a host."""
@@ -55,7 +56,7 @@
         resp, body = self.put("os-hosts/%s" % str(hostname), request_body)
         body = json.loads(body)
         self.validate_response(v2_schema.update_host, resp, body)
-        return resp, body
+        return service_client.ResponseBody(resp, body)
 
     def startup_host(self, hostname):
         """Startup a host."""
@@ -63,7 +64,7 @@
         resp, body = self.get("os-hosts/%s/startup" % str(hostname))
         body = json.loads(body)
         self.validate_response(v2_schema.startup_host, resp, body)
-        return resp, body['host']
+        return service_client.ResponseBody(resp, body['host'])
 
     def shutdown_host(self, hostname):
         """Shutdown a host."""
@@ -71,7 +72,7 @@
         resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
         body = json.loads(body)
         self.validate_response(v2_schema.shutdown_host, resp, body)
-        return resp, body['host']
+        return service_client.ResponseBody(resp, body['host'])
 
     def reboot_host(self, hostname):
         """reboot a host."""
@@ -79,4 +80,4 @@
         resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
         body = json.loads(body)
         self.validate_response(v2_schema.reboot_host, resp, body)
-        return resp, body['host']
+        return service_client.ResponseBody(resp, body['host'])
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 52b50c8..37be874 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -17,6 +17,7 @@
 
 from tempest.api_schema.response.compute import hypervisors as common_schema
 from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
+from tempest.common import service_client
 from tempest.services.compute.json import base
 
 
@@ -28,7 +29,7 @@
         body = json.loads(body)
         self.validate_response(common_schema.common_hypervisors_detail,
                                resp, body)
-        return resp, body['hypervisors']
+        return service_client.ResponseBodyList(resp, body['hypervisors'])
 
     def get_hypervisor_list_details(self):
         """Show detailed hypervisors information."""
@@ -36,7 +37,7 @@
         body = json.loads(body)
         self.validate_response(common_schema.common_list_hypervisors_detail,
                                resp, body)
-        return resp, body['hypervisors']
+        return service_client.ResponseBodyList(resp, body['hypervisors'])
 
     def get_hypervisor_show_details(self, hyper_id):
         """Display the details of the specified hypervisor."""
@@ -44,28 +45,28 @@
         body = json.loads(body)
         self.validate_response(common_schema.common_show_hypervisor,
                                resp, body)
-        return resp, body['hypervisor']
+        return service_client.ResponseBody(resp, body['hypervisor'])
 
     def get_hypervisor_servers(self, hyper_name):
         """List instances belonging to the specified hypervisor."""
         resp, body = self.get('os-hypervisors/%s/servers' % hyper_name)
         body = json.loads(body)
         self.validate_response(v2schema.hypervisors_servers, resp, body)
-        return resp, body['hypervisors']
+        return service_client.ResponseBodyList(resp, body['hypervisors'])
 
     def get_hypervisor_stats(self):
         """Get hypervisor statistics over all compute nodes."""
         resp, body = self.get('os-hypervisors/statistics')
         body = json.loads(body)
         self.validate_response(common_schema.hypervisor_statistics, resp, body)
-        return resp, body['hypervisor_statistics']
+        return service_client.ResponseBody(resp, body['hypervisor_statistics'])
 
     def get_hypervisor_uptime(self, hyper_id):
         """Display the uptime of the specified hypervisor."""
         resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id)
         body = json.loads(body)
         self.validate_response(common_schema.hypervisor_uptime, resp, body)
-        return resp, body['hypervisor']
+        return service_client.ResponseBody(resp, body['hypervisor'])
 
     def search_hypervisor(self, hyper_name):
         """Search specified hypervisor."""
@@ -73,4 +74,4 @@
         body = json.loads(body)
         self.validate_response(common_schema.common_hypervisors_detail,
                                resp, body)
-        return resp, body['hypervisors']
+        return service_client.ResponseBodyList(resp, body['hypervisors'])
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index 8d73c37..52662fa 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -18,6 +18,7 @@
 import urllib
 
 from tempest.api_schema.response.compute import services as schema
+from tempest.common import service_client
 from tempest.services.compute.json import base
 
 
@@ -31,7 +32,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.validate_response(schema.list_services, resp, body)
-        return resp, body['services']
+        return service_client.ResponseBodyList(resp, body['services'])
 
     def enable_service(self, host_name, binary):
         """
@@ -43,7 +44,7 @@
         resp, body = self.put('os-services/enable', post_body)
         body = json.loads(body)
         self.validate_response(schema.enable_service, resp, body)
-        return resp, body['service']
+        return service_client.ResponseBody(resp, body['service'])
 
     def disable_service(self, host_name, binary):
         """
@@ -54,4 +55,4 @@
         post_body = json.dumps({'binary': binary, 'host': host_name})
         resp, body = self.put('os-services/disable', post_body)
         body = json.loads(body)
-        return resp, body['service']
+        return service_client.ResponseBody(resp, body['service'])
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 513d2cf..4d45515 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -82,8 +82,10 @@
         self._router_ids = set()
 
     def update(self, *args, **kwargs):
-        result = self.client.update_subnet(subnet=self.id, *args, **kwargs)
-        super(DeletableSubnet, self).update(**result['subnet'])
+        result = self.client.update_subnet(self.id,
+                                           *args,
+                                           **kwargs)
+        return super(DeletableSubnet, self).update(**result['subnet'])
 
     def add_to_router(self, router_id):
         self._router_ids.add(router_id)