Merge "Make fixed_ips_client use **kwargs"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 1095e77..27d65e6 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -432,6 +432,11 @@
 # value)
 #attach_encrypted_volume = true
 
+# Does the test environment support creating instances with multiple
+# ports on the same network? This is only valid when using Neutron.
+# (boolean value)
+#allow_duplicate_networks = false
+
 
 [dashboard]
 
diff --git a/setup.cfg b/setup.cfg
index 5c78632..36b2270 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -18,6 +18,12 @@
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.4
 
+[files]
+packages =
+    tempest
+data_files =
+    /etc/tempest = etc/*
+
 [entry_points]
 console_scripts =
     verify-tempest-config = tempest.cmd.verify_tempest_config:main
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 91e55d6..9334fb6 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -106,7 +106,7 @@
 
         # set the metadata of the aggregate
         meta = {"key": "value"}
-        body = self.client.set_metadata(aggregate['id'], meta)
+        body = self.client.set_metadata(aggregate['id'], metadata=meta)
         self.assertEqual(meta, body["metadata"])
 
         # verify the metadata has been set
@@ -130,9 +130,10 @@
         new_aggregate_name = aggregate_name + '_new'
         new_az_name = az_name + '_new'
 
-        resp_aggregate = self.client.update_aggregate(aggregate_id,
-                                                      new_aggregate_name,
-                                                      new_az_name)
+        resp_aggregate = self.client.update_aggregate(
+            aggregate_id,
+            name=new_aggregate_name,
+            availability_zone=new_az_name)
         self.assertEqual(new_aggregate_name, resp_aggregate['name'])
         self.assertEqual(new_az_name, resp_aggregate['availability_zone'])
 
@@ -150,13 +151,13 @@
         aggregate = self.client.create_aggregate(name=aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
-        body = self.client.add_host(aggregate['id'], self.host)
+        body = self.client.add_host(aggregate['id'], host=self.host)
         self.assertEqual(aggregate_name, body['name'])
         self.assertEqual(aggregate['availability_zone'],
                          body['availability_zone'])
         self.assertIn(self.host, body['hosts'])
 
-        body = self.client.remove_host(aggregate['id'], self.host)
+        body = self.client.remove_host(aggregate['id'], host=self.host)
         self.assertEqual(aggregate_name, body['name'])
         self.assertEqual(aggregate['availability_zone'],
                          body['availability_zone'])
@@ -169,8 +170,9 @@
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         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)
+        self.client.add_host(aggregate['id'], host=self.host)
+        self.addCleanup(self.client.remove_host, aggregate['id'],
+                        host=self.host)
 
         aggregates = self.client.list_aggregates()
         aggs = filter(lambda x: x['id'] == aggregate['id'], aggregates)
@@ -187,8 +189,9 @@
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         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)
+        self.client.add_host(aggregate['id'], host=self.host)
+        self.addCleanup(self.client.remove_host, aggregate['id'],
+                        host=self.host)
 
         body = self.client.show_aggregate(aggregate['id'])
         self.assertEqual(aggregate_name, body['name'])
@@ -204,8 +207,9 @@
         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)
-        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
+        self.client.add_host(aggregate['id'], host=self.host)
+        self.addCleanup(self.client.remove_host, aggregate['id'],
+                        host=self.host)
         server_name = data_utils.rand_name('test_server')
         admin_servers_client = self.os_adm.servers_client
         server = self.create_test_server(name=server_name,
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 74a8547..231c88f 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -143,7 +143,7 @@
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(lib_exc.NotFound, self.client.add_host,
-                          aggregate['id'], non_exist_host)
+                          aggregate['id'], host=non_exist_host)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51')
@@ -155,7 +155,7 @@
 
         self.assertRaises(lib_exc.Forbidden,
                           self.user_client.add_host,
-                          aggregate['id'], self.host)
+                          aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950')
@@ -165,11 +165,12 @@
         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)
+        self.client.add_host(aggregate['id'], host=self.host)
+        self.addCleanup(self.client.remove_host, aggregate['id'],
+                        host=self.host)
 
         self.assertRaises(lib_exc.Conflict, self.client.add_host,
-                          aggregate['id'], self.host)
+                          aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9')
@@ -179,12 +180,13 @@
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         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)
+        self.client.add_host(aggregate['id'], host=self.host)
+        self.addCleanup(self.client.remove_host, aggregate['id'],
+                        host=self.host)
 
         self.assertRaises(lib_exc.Forbidden,
                           self.user_client.remove_host,
-                          aggregate['id'], self.host)
+                          aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d')
@@ -195,4 +197,4 @@
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
 
         self.assertRaises(lib_exc.NotFound, self.client.remove_host,
-                          aggregate['id'], non_exist_host)
+                          aggregate['id'], host=non_exist_host)
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 39447b8..23a9cb3 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -65,6 +65,20 @@
         cls.password = cls.server_initial['adminPass']
         cls.server = cls.client.show_server(cls.server_initial['id'])
 
+    def _create_net_subnet_ret_net_from_cidr(self, cidr):
+        name_net = data_utils.rand_name(self.__class__.__name__)
+        net = self.network_client.create_network(name=name_net)
+        self.addCleanup(self.network_client.delete_network,
+                        net['network']['id'])
+
+        subnet = self.network_client.create_subnet(
+            network_id=net['network']['id'],
+            cidr=cidr,
+            ip_version=4)
+        self.addCleanup(self.network_client.delete_subnet,
+                        subnet['subnet']['id'])
+        return net
+
     @test.attr(type='smoke')
     @test.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f')
     def test_verify_server_details(self):
@@ -147,29 +161,8 @@
     def test_verify_multiple_nics_order(self):
         # Verify that the networks order given at the server creation is
         # preserved within the server.
-        name_net1 = data_utils.rand_name(self.__class__.__name__)
-        net1 = self.network_client.create_network(name=name_net1)
-        self.addCleanup(self.network_client.delete_network,
-                        net1['network']['id'])
-
-        name_net2 = data_utils.rand_name(self.__class__.__name__)
-        net2 = self.network_client.create_network(name=name_net2)
-        self.addCleanup(self.network_client.delete_network,
-                        net2['network']['id'])
-
-        subnet1 = self.network_client.create_subnet(
-            network_id=net1['network']['id'],
-            cidr='19.80.0.0/24',
-            ip_version=4)
-        self.addCleanup(self.network_client.delete_subnet,
-                        subnet1['subnet']['id'])
-
-        subnet2 = self.network_client.create_subnet(
-            network_id=net2['network']['id'],
-            cidr='19.86.0.0/24',
-            ip_version=4)
-        self.addCleanup(self.network_client.delete_subnet,
-                        subnet2['subnet']['id'])
+        net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24')
+        net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24')
 
         networks = [{'uuid': net1['network']['id']},
                     {'uuid': net2['network']['id']}]
@@ -196,13 +189,50 @@
         # other times ['19.80.0.3', '19.86.0.3']. So we check if the first
         # address is in first network, similarly second address is in second
         # network.
-        addr = [addresses[name_net1][0]['addr'],
-                addresses[name_net2][0]['addr']]
+        addr = [addresses[net1['network']['name']][0]['addr'],
+                addresses[net2['network']['name']][0]['addr']]
         networks = [netaddr.IPNetwork('19.80.0.0/24'),
                     netaddr.IPNetwork('19.86.0.0/24')]
         for address, network in zip(addr, networks):
             self.assertIn(address, network)
 
+    @test.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2')
+    @testtools.skipUnless(CONF.service_available.neutron,
+                          'Neutron service must be available.')
+    # The below skipUnless should be removed once Kilo-eol happens.
+    @testtools.skipUnless(CONF.compute_feature_enabled.
+                          allow_duplicate_networks,
+                          'Duplicate networks must be allowed')
+    def test_verify_duplicate_network_nics(self):
+        # Verify that server creation does not fail when more than one nic
+        # is created on the same network.
+        net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24')
+        net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24')
+
+        networks = [{'uuid': net1['network']['id']},
+                    {'uuid': net2['network']['id']},
+                    {'uuid': net1['network']['id']}]
+
+        server_multi_nics = self.create_test_server(
+            networks=networks, wait_until='ACTIVE')
+
+        def cleanup_server():
+            self.client.delete_server(server_multi_nics['id'])
+            self.client.wait_for_server_termination(server_multi_nics['id'])
+
+        self.addCleanup(cleanup_server)
+
+        addresses = self.client.list_addresses(server_multi_nics['id'])
+
+        addr = [addresses[net1['network']['name']][0]['addr'],
+                addresses[net2['network']['name']][0]['addr'],
+                addresses[net1['network']['name']][1]['addr']]
+        networks = [netaddr.IPNetwork('19.80.0.0/24'),
+                    netaddr.IPNetwork('19.86.0.0/24'),
+                    netaddr.IPNetwork('19.80.0.0/24')]
+        for address, network in zip(addr, networks):
+            self.assertIn(address, network)
+
 
 class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
     disk_config = 'AUTO'
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 4f54562..6a8fbec 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -156,26 +156,21 @@
         network = self.create_network()
         subnet = self.create_subnet(network)
         self.addCleanup(self.client.delete_subnet, subnet['id'])
-        # Create two ports specifying a fixed_ips
-        address = self._get_ipaddress_from_tempest_conf()
-        _fixed_ip_1 = str(address + 3)
-        _fixed_ip_2 = str(address + 4)
-        fixed_ips_1 = [{'ip_address': _fixed_ip_1}]
-        port_1 = self.client.create_port(network_id=network['id'],
-                                         fixed_ips=fixed_ips_1)
+        # Create two ports
+        port_1 = self.client.create_port(network_id=network['id'])
         self.addCleanup(self.client.delete_port, port_1['port']['id'])
-        fixed_ips_2 = [{'ip_address': _fixed_ip_2}]
-        port_2 = self.client.create_port(network_id=network['id'],
-                                         fixed_ips=fixed_ips_2)
+        port_2 = self.client.create_port(network_id=network['id'])
         self.addCleanup(self.client.delete_port, port_2['port']['id'])
         # List ports filtered by fixed_ips
-        fixed_ips = 'ip_address=' + _fixed_ip_1
+        port_1_fixed_ip = port_1['port']['fixed_ips'][0]['ip_address']
+        fixed_ips = 'ip_address=' + port_1_fixed_ip
         port_list = self.client.list_ports(fixed_ips=fixed_ips)
+        # Check that we got the desired port
         ports = port_list['ports']
         self.assertEqual(len(ports), 1)
         self.assertEqual(ports[0]['id'], port_1['port']['id'])
         self.assertEqual(ports[0]['fixed_ips'][0]['ip_address'],
-                         _fixed_ip_1)
+                         port_1_fixed_ip)
         self.assertEqual(ports[0]['network_id'], network['id'])
 
     @test.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72')
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index f8ae5eb..b67a6d2 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -62,6 +62,7 @@
         super(BaseVolumeTest, cls).setup_clients()
         cls.servers_client = cls.os.servers_client
         cls.networks_client = cls.os.networks_client
+        cls.images_client = cls.os.images_client
 
         if cls._api_version == 1:
             cls.snapshots_client = cls.os.snapshots_client
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 29c21ed..a90f9ca 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -131,7 +131,11 @@
     @test.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
     @test.services('image')
     def test_volume_create_get_update_delete_from_image(self):
-        self._volume_create_get_update_delete(imageRef=CONF.compute.image_ref)
+        image = self.images_client.show_image(CONF.compute.image_ref)
+        min_disk = image.get('minDisk')
+        disk_size = max(min_disk, CONF.volume.volume_size)
+        self._volume_create_get_update_delete(
+            imageRef=CONF.compute.image_ref, size=disk_size)
 
     @test.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1')
     def test_volume_create_get_update_delete_as_clone(self):
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 1de20d6..dcdf7c5 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -1,12 +1,12 @@
 #!/usr/bin/env python
 
-# Copyright 2014 Dell Inc.
+# Copyright 2015 Dell Inc.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
 #    a copy of the License at
 #
-#         http://www.apache.org/licenses/LICENSE-2.0
+#        http://www.apache.org/licenses/LICENSE-2.0
 #
 #    Unless required by applicable law or agreed to in writing, software
 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
@@ -153,9 +153,8 @@
         for snap in snaps:
             try:
                 client.delete_snapshot(snap['id'])
-            except Exception as e:
-                LOG.exception("Delete Snapshot exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Snapshot exception.")
 
     def dry_run(self):
         snaps = self.list()
@@ -180,9 +179,8 @@
         for server in servers:
             try:
                 client.delete_server(server['id'])
-            except Exception as e:
-                LOG.exception("Delete Server exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Server exception.")
 
     def dry_run(self):
         servers = self.list()
@@ -203,9 +201,8 @@
         for sg in sgs:
             try:
                 client.delete_server_group(sg['id'])
-            except Exception as e:
-                LOG.exception("Delete Server Group exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Server Group exception.")
 
     def dry_run(self):
         sgs = self.list()
@@ -229,9 +226,8 @@
         for stack in stacks:
             try:
                 client.delete_stack(stack['id'])
-            except Exception as e:
-                LOG.exception("Delete Stack exception: %s " % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Stack exception.")
 
     def dry_run(self):
         stacks = self.list()
@@ -256,9 +252,8 @@
             try:
                 name = k['keypair']['name']
                 client.delete_keypair(name)
-            except Exception as e:
-                LOG.exception("Delete Keypairs exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Keypairs exception.")
 
     def dry_run(self):
         keypairs = self.list()
@@ -283,8 +278,8 @@
         for g in secgrp_del:
             try:
                 client.delete_security_group(g['id'])
-            except Exception as e:
-                LOG.exception("Delete Security Groups exception: %s" % e)
+            except Exception:
+                LOG.exception("Delete Security Groups exception.")
 
     def dry_run(self):
         secgrp_del = self.list()
@@ -308,9 +303,8 @@
         for f in floating_ips:
             try:
                 client.delete_floating_ip(f['id'])
-            except Exception as e:
-                LOG.exception("Delete Floating IPs exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Floating IPs exception.")
 
     def dry_run(self):
         floating_ips = self.list()
@@ -334,9 +328,8 @@
         for v in vols:
             try:
                 client.delete_volume(v['id'])
-            except Exception as e:
-                LOG.exception("Delete Volume exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Volume exception.")
 
     def dry_run(self):
         vols = self.list()
@@ -352,9 +345,8 @@
         client = self.client
         try:
             client.delete_quota_set(self.tenant_id)
-        except Exception as e:
-            LOG.exception("Delete Volume Quotas exception: %s" % e)
-            pass
+        except Exception:
+            LOG.exception("Delete Volume Quotas exception.")
 
     def dry_run(self):
         quotas = self.client.show_quota_usage(self.tenant_id)
@@ -371,9 +363,8 @@
         client = self.client
         try:
             client.delete_quota_set(self.tenant_id)
-        except Exception as e:
-            LOG.exception("Delete Quotas exception: %s" % e)
-            pass
+        except Exception:
+            LOG.exception("Delete Quotas exception.")
 
     def dry_run(self):
         client = self.limits_client
@@ -411,9 +402,8 @@
         for n in networks:
             try:
                 client.delete_network(n['id'])
-            except Exception as e:
-                LOG.exception("Delete Network exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Network exception.")
 
     def dry_run(self):
         networks = self.list()
@@ -436,9 +426,8 @@
         for flip in flips:
             try:
                 client.delete_floatingip(flip['id'])
-            except Exception as e:
-                LOG.exception("Delete Network Floating IP exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Network Floating IP exception.")
 
     def dry_run(self):
         flips = self.list()
@@ -471,9 +460,8 @@
                     subid = port['fixed_ips'][0]['subnet_id']
                     client.remove_router_interface_with_subnet_id(rid, subid)
                 client.delete_router(rid)
-            except Exception as e:
-                LOG.exception("Delete Router exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Router exception.")
 
     def dry_run(self):
         routers = self.list()
@@ -496,9 +484,8 @@
         for hm in hms:
             try:
                 client.delete_health_monitor(hm['id'])
-            except Exception as e:
-                LOG.exception("Delete Health Monitor exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Health Monitor exception.")
 
     def dry_run(self):
         hms = self.list()
@@ -521,9 +508,8 @@
         for member in members:
             try:
                 client.delete_member(member['id'])
-            except Exception as e:
-                LOG.exception("Delete Member exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Member exception.")
 
     def dry_run(self):
         members = self.list()
@@ -546,9 +532,8 @@
         for vip in vips:
             try:
                 client.delete_vip(vip['id'])
-            except Exception as e:
-                LOG.exception("Delete VIP exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete VIP exception.")
 
     def dry_run(self):
         vips = self.list()
@@ -571,9 +556,8 @@
         for pool in pools:
             try:
                 client.delete_pool(pool['id'])
-            except Exception as e:
-                LOG.exception("Delete Pool exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Pool exception.")
 
     def dry_run(self):
         pools = self.list()
@@ -596,9 +580,8 @@
         for rule in rules:
             try:
                 client.delete_metering_label_rule(rule['id'])
-            except Exception as e:
-                LOG.exception("Delete Metering Label Rule exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Metering Label Rule exception.")
 
     def dry_run(self):
         rules = self.list()
@@ -621,9 +604,8 @@
         for label in labels:
             try:
                 client.delete_metering_label(label['id'])
-            except Exception as e:
-                LOG.exception("Delete Metering Label exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Metering Label exception.")
 
     def dry_run(self):
         labels = self.list()
@@ -648,9 +630,8 @@
         for port in ports:
             try:
                 client.delete_port(port['id'])
-            except Exception as e:
-                LOG.exception("Delete Port exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Port exception.")
 
     def dry_run(self):
         ports = self.list()
@@ -675,9 +656,8 @@
         for subnet in subnets:
             try:
                 client.delete_subnet(subnet['id'])
-            except Exception as e:
-                LOG.exception("Delete Subnet exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Subnet exception.")
 
     def dry_run(self):
         subnets = self.list()
@@ -702,9 +682,8 @@
         for alarm in alarms:
             try:
                 client.delete_alarm(alarm['id'])
-            except Exception as e:
-                LOG.exception("Delete Alarms exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Alarms exception.")
 
     def dry_run(self):
         alarms = self.list()
@@ -737,9 +716,8 @@
         for flavor in flavors:
             try:
                 client.delete_flavor(flavor['id'])
-            except Exception as e:
-                LOG.exception("Delete Flavor exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Flavor exception.")
 
     def dry_run(self):
         flavors = self.list()
@@ -775,9 +753,8 @@
         for image in images:
             try:
                 client.delete_image(image['id'])
-            except Exception as e:
-                LOG.exception("Delete Image exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Image exception.")
 
     def dry_run(self):
         images = self.list()
@@ -823,9 +800,8 @@
         for user in users:
             try:
                 client.delete_user(user['id'])
-            except Exception as e:
-                LOG.exception("Delete User exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete User exception.")
 
     def dry_run(self):
         users = self.list()
@@ -852,8 +828,8 @@
                           and role['name'] != CONF.identity.admin_role)]
                 LOG.debug("List count, %s Roles after reconcile" % len(roles))
             return roles
-        except Exception as ex:
-            LOG.exception("Cannot retrieve Roles, exception: %s" % ex)
+        except Exception:
+            LOG.exception("Cannot retrieve Roles.")
             return []
 
     def delete(self):
@@ -862,9 +838,8 @@
         for role in roles:
             try:
                 client.delete_role(role['id'])
-            except Exception as e:
-                LOG.exception("Delete Role exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Role exception.")
 
     def dry_run(self):
         roles = self.list()
@@ -900,9 +875,8 @@
         for tenant in tenants:
             try:
                 client.delete_tenant(tenant['id'])
-            except Exception as e:
-                LOG.exception("Delete Tenant exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Tenant exception.")
 
     def dry_run(self):
         tenants = self.list()
@@ -938,9 +912,8 @@
             try:
                 client.update_domain(domain['id'], enabled=False)
                 client.delete_domain(domain['id'])
-            except Exception as e:
-                LOG.exception("Delete Domain exception: %s" % e)
-                pass
+            except Exception:
+                LOG.exception("Delete Domain exception.")
 
     def dry_run(self):
         domains = self.list()
diff --git a/tempest/config.py b/tempest/config.py
index 7382088..5ea4d10 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -22,6 +22,8 @@
 
 from oslo_log import log as logging
 
+from tempest.test_discover import plugins
+
 
 # TODO(marun) Replace use of oslo_config's global ConfigOpts
 # (cfg.CONF) instance with a local instance (cfg.ConfigOpts()) once
@@ -388,6 +390,14 @@
                      'encrypted volume to a running server instance? This may '
                      'depend on the combination of compute_driver in nova and '
                      'the volume_driver(s) in cinder.'),
+    # TODO(mriedem): Remove allow_duplicate_networks once kilo-eol happens
+    # since the option was removed from nova in Liberty and is the default
+    # behavior starting in Liberty.
+    cfg.BoolOpt('allow_duplicate_networks',
+                default=False,
+                help='Does the test environment support creating instances '
+                     'with multiple ports on the same network? This is only '
+                     'valid when using Neutron.'),
 ]
 
 
@@ -1184,8 +1194,12 @@
 
 
 def register_opts():
+    ext_plugins = plugins.TempestTestPluginManager()
+    # Register in-tree tempest config options
     for g, o in _opts:
         register_opt_group(_CONF, g, o)
+    # Call external plugin config option registration
+    ext_plugins.register_plugin_opts(_CONF)
 
 
 def list_opts():
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 02d1171..f5f4a61 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -64,12 +64,12 @@
         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=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=host)
         self.assertNotIn(host, aggregate['hosts'])
 
     def _check_aggregate_details(self, aggregate, aggregate_name, azone,
@@ -85,7 +85,7 @@
 
     def _set_aggregate_metadata(self, aggregate, meta):
         aggregate = self.aggregates_client.set_metadata(aggregate['id'],
-                                                        meta)
+                                                        metadata=meta)
 
         for key, value in meta.items():
             self.assertEqual(meta[key], aggregate['metadata'][key])
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 28d4ff5..4114b8b 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -45,13 +45,9 @@
         self.validate_response(schema.create_aggregate, resp, body)
         return service_client.ResponseBody(resp, body['aggregate'])
 
-    def update_aggregate(self, aggregate_id, name, availability_zone=None):
+    def update_aggregate(self, aggregate_id, **kwargs):
         """Update a aggregate."""
-        put_body = {
-            'name': name,
-            'availability_zone': availability_zone
-        }
-        put_body = json.dumps({'aggregate': put_body})
+        put_body = json.dumps({'aggregate': kwargs})
         resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body)
 
         body = json.loads(body)
@@ -76,36 +72,27 @@
         """Returns the primary type of resource this client works with."""
         return 'aggregate'
 
-    def add_host(self, aggregate_id, host):
+    def add_host(self, aggregate_id, **kwargs):
         """Adds a host to the given aggregate."""
-        post_body = {
-            'host': host,
-        }
-        post_body = json.dumps({'add_host': post_body})
+        post_body = json.dumps({'add_host': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.aggregate_add_remove_host, resp, body)
         return service_client.ResponseBody(resp, body['aggregate'])
 
-    def remove_host(self, aggregate_id, host):
+    def remove_host(self, aggregate_id, **kwargs):
         """Removes a host from the given aggregate."""
-        post_body = {
-            'host': host,
-        }
-        post_body = json.dumps({'remove_host': post_body})
+        post_body = json.dumps({'remove_host': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.aggregate_add_remove_host, resp, body)
         return service_client.ResponseBody(resp, body['aggregate'])
 
-    def set_metadata(self, aggregate_id, meta):
+    def set_metadata(self, aggregate_id, **kwargs):
         """Replaces the aggregate's existing metadata with new metadata."""
-        post_body = {
-            'metadata': meta,
-        }
-        post_body = json.dumps({'set_metadata': post_body})
+        post_body = json.dumps({'set_metadata': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                                post_body)
         body = json.loads(body)
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index 2701f02..45cd609 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -40,6 +40,17 @@
         """
         return
 
+    @abc.abstractmethod
+    def register_opts(self, conf):
+        """Method to add additional configuration options to tempest. This
+        method will be run for the plugin during the register_opts() function
+        in tempest.config
+
+        :param ConfigOpts conf: The conf object that can be used to register
+            additional options on.
+        """
+        return
+
 
 @misc.singleton
 class TempestTestPluginManager(object):
@@ -64,3 +75,7 @@
         for plug in self.ext_plugins:
             load_tests_dict[plug.name] = plug.obj.load_tests()
         return load_tests_dict
+
+    def register_plugin_opts(self, conf):
+        for plug in self.ext_plugins:
+            plug.obj.register_opts(conf)
diff --git a/test-requirements.txt b/test-requirements.txt
index 8fcf071..65e3531 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,7 +7,6 @@
 python-subunit>=0.0.18
 oslosphinx>=2.5.0 # Apache-2.0
 mox>=0.5.3
-mock>=1.1;python_version!='2.6'
-mock==1.0.1;python_version=='2.6'
+mock>=1.2
 coverage>=3.6
 oslotest>=1.7.0 # Apache-2.0