Merge "Fix verify_tempest_config to not leak a tenant"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index c1b5146..4418b9d 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -375,6 +375,11 @@
# https://bugs.launchpad.net/nova/+bug/1398999 (boolean value)
#block_migrate_cinder_iscsi = false
+# Does the test system allow live-migration of paused instances? Note,
+# this is more than just the ANDing of paused and live_migrate, but
+# all 3 should be set to True to run those tests (boolean value)
+#live_migrate_paused_instances = false
+
# Enable VNC console. This configuration value should be same as
# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
#vnc_console = false
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index e9068f3..5ad05cc 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -28,7 +29,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/baremetal/admin/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
index ee6bb9c..ece4471 100644
--- a/tempest/api/baremetal/admin/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
from tempest_lib import exceptions as lib_exc
@@ -31,7 +32,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 6634290..9da7901 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -14,7 +14,8 @@
# under the License.
import datetime
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api.compute import base
from tempest import test
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index ec9ad19..97d665b 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -14,8 +14,8 @@
# under the License.
import datetime
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api.compute import base
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 8a92326..d3b1f5e 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -84,10 +84,15 @@
self.volumes_client.wait_for_volume_status(volume_id, 'available')
self.volumes_client.delete_volume(volume_id)
- @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
- @testtools.skipIf(not CONF.compute_feature_enabled.live_migration,
- 'Live migration not available')
- def test_live_block_migration(self):
+ def _test_live_block_migration(self, state='ACTIVE'):
+ """Tests live block migration between two hosts.
+
+ Requires CONF.compute_feature_enabled.live_migration to be True.
+
+ :param state: The vm_state the migrated server should be in before and
+ after the live migration. Supported values are 'ACTIVE'
+ and 'PAUSED'.
+ """
# Live block migrate an instance to another host
if len(self._get_compute_hostnames()) < 2:
raise self.skipTest(
@@ -95,10 +100,33 @@
server_id = self._get_an_active_server()
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
+
+ if state == 'PAUSED':
+ self.admin_servers_client.pause_server(server_id)
+ self.admin_servers_client.wait_for_server_status(server_id, state)
+
self._migrate_server_to(server_id, target_host)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+ self.servers_client.wait_for_server_status(server_id, state)
self.assertEqual(target_host, self._get_host_for_server(server_id))
+ @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ def test_live_block_migration(self):
+ self._test_live_block_migration()
+
+ @test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
+ @testtools.skipUnless(CONF.compute_feature_enabled
+ .live_migrate_paused_instances,
+ 'Live migration of paused instances is not '
+ 'available.')
+ def test_live_block_migration_paused(self):
+ self._test_live_block_migration(state='PAUSED')
+
@test.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
CONF.compute_feature_enabled.
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d0dfc87..a17f581 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
+
from tempest.api.compute import base
from tempest import test
@@ -48,7 +50,7 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
self.assertTrue(len(addresses) >= 1)
- for network_name, network_addresses in addresses.iteritems():
+ for network_name, network_addresses in six.iteritems(addresses):
self.assertTrue(len(network_addresses) >= 1)
for address in network_addresses:
self.assertTrue(address['addr'])
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 86fbc54..46d6651 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base
@@ -62,7 +63,7 @@
quota_set = self.admin_client.update_quotas(tenant_id,
**new_quotas)
self.addCleanup(self.admin_client.reset_quotas, tenant_id)
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Confirm our tenant is listed among tenants with non default quotas
@@ -76,7 +77,7 @@
# Confirm from API quotas were changed as requested for tenant
quota_set = self.admin_client.show_quotas(tenant_id)
quota_set = quota_set['quota']
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Reset quotas to default and confirm
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 253d779..ca08fbd 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -16,6 +16,7 @@
import netaddr
import random
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -127,7 +128,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
self._clean_network()
self.assertEqual(eui_ip, real_ip,
@@ -203,8 +204,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self.client.delete_port(port['id'])
self.ports.pop()
body = self.client.list_ports()
@@ -256,8 +257,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self._clean_network()
self.assertTrue({real_eui_ip,
real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
@@ -284,7 +285,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
port = self.create_port(self.network)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
@@ -311,7 +312,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
subnet["allocation_pools"][0]["end"])
@@ -389,7 +390,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet, port = self._create_subnet_router(kwargs)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
self._clean_network()
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index d007fb0..0622e87 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -145,7 +146,7 @@
def test_show_firewall_rule(self):
# show a created firewall rule
fw_rule = self.client.show_firewall_rule(self.fw_rule['id'])
- for key, value in fw_rule['firewall_rule'].iteritems():
+ for key, value in six.iteritems(fw_rule['firewall_rule']):
self.assertEqual(self.fw_rule[key], value)
@test.idempotent_id('1086dd93-a4c0-4bbb-a1bd-6d4bc62c199f')
@@ -187,7 +188,7 @@
# show a created firewall policy
fw_policy = self.client.show_firewall_policy(self.fw_policy['id'])
fw_policy = fw_policy['firewall_policy']
- for key, value in fw_policy.iteritems():
+ for key, value in six.iteritems(fw_policy):
self.assertEqual(self.fw_policy[key], value)
@test.idempotent_id('02082a03-3cdd-4789-986a-1327dd80bfb7')
@@ -216,7 +217,7 @@
firewall = self.client.show_firewall(firewall_id)
firewall = firewall['firewall']
- for key, value in firewall.iteritems():
+ for key, value in six.iteritems(firewall):
if key == 'status':
continue
self.assertEqual(created_firewall[key], value)
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index ace9f61..38a6fe9 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
@@ -75,7 +76,7 @@
body = create_obj(**kwargs)
obj = body[obj_name]
self.addCleanup(delete_obj, obj['id'])
- for key, value in obj.iteritems():
+ for key, value in six.iteritems(obj):
# It is not relevant to filter by all arguments. That is why
# there is a list of attr to except
if key not in attr_exceptions:
@@ -168,7 +169,7 @@
# Verifies the details of a vip
body = self.client.show_vip(self.vip['id'])
vip = body['vip']
- for key, value in vip.iteritems():
+ for key, value in six.iteritems(vip):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.vip[key], value)
@@ -185,7 +186,7 @@
# Verifies the details of a pool
body = self.client.show_pool(pool['id'])
shown_pool = body['pool']
- for key, value in pool.iteritems():
+ for key, value in six.iteritems(pool):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(value, shown_pool[key])
@@ -243,7 +244,7 @@
# Verifies the details of a member
body = self.client.show_member(self.member['id'])
member = body['member']
- for key, value in member.iteritems():
+ for key, value in six.iteritems(member):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.member[key], value)
@@ -316,7 +317,7 @@
# Verifies the details of a health_monitor
body = self.client.show_health_monitor(self.health_monitor['id'])
health_monitor = body['health_monitor']
- for key, value in health_monitor.iteritems():
+ for key, value in six.iteritems(health_monitor):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.health_monitor[key], value)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 97273a6..5e3e374 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -15,6 +15,7 @@
import itertools
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -162,7 +163,7 @@
**kwargs)
compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
mask_bits=mask_bits, **kwargs)
- compare_args = dict((k, v) for k, v in compare_args_full.iteritems()
+ compare_args = dict((k, v) for k, v in six.iteritems(compare_args_full)
if v is not None)
if 'dns_nameservers' in set(subnet).intersection(compare_args):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 4362926..35072b4 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -14,6 +14,7 @@
# under the License.
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base_routers as base
@@ -176,7 +177,7 @@
self.assertIsNone(actual_ext_gw_info)
return
# Verify only keys passed in exp_ext_gw_info
- for k, v in exp_ext_gw_info.iteritems():
+ for k, v in six.iteritems(exp_ext_gw_info):
self.assertEqual(v, actual_ext_gw_info[k])
def _verify_gateway_port(self, router_id):
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 718168b..9fe2a56 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -82,7 +83,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
@@ -245,7 +246,7 @@
# Confirm that update was successful by verifying using 'show'
body = self.client.show_ikepolicy(ikepolicy['id'])
ike_policy = body['ikepolicy']
- for key, value in new_ike.iteritems():
+ for key, value in six.iteritems(new_ike):
self.assertIn(key, ike_policy)
self.assertEqual(value, ike_policy[key])
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 814b46d..24c7c63 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.volume import base
@@ -57,7 +58,7 @@
**new_quota_set)
cleanup_quota_set = dict(
- (k, v) for k, v in default_quota_set.iteritems()
+ (k, v) for k, v in six.iteritems(default_quota_set)
if k in QUOTA_KEYS)
self.addCleanup(self.quotas_client.update_quota_set,
self.demo_tenant_id, **cleanup_quota_set)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index b2311b0..4e2af76 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -114,6 +114,7 @@
import netaddr
from oslo_log import log as logging
from oslo_utils import timeutils
+import six
from tempest_lib import auth
from tempest_lib import exceptions as lib_exc
import yaml
@@ -416,7 +417,7 @@
that things like tenantId didn't drift across versions.
"""
LOG.info("checking users")
- for name, user in self.users.iteritems():
+ for name, user in six.iteritems(self.users):
client = keystone_admin()
found = client.identity.get_user(user['id'])
self.assertEqual(found['name'], user['name'])
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 93c8bcf..650faf1 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -17,6 +17,7 @@
from oslo_concurrency import lockutils
from oslo_log import log as logging
+import six
import yaml
from tempest import clients
@@ -75,7 +76,7 @@
if 'resources' in account:
resources = account.pop('resources')
temp_hash = hashlib.md5()
- temp_hash.update(str(account))
+ temp_hash.update(six.text_type(account).encode('utf-8'))
temp_hash_key = temp_hash.hexdigest()
hash_dict['creds'][temp_hash_key] = account
for role in roles:
@@ -244,17 +245,19 @@
def get_creds_by_roles(self, roles, force_new=False):
roles = list(set(roles))
- exist_creds = self.isolated_creds.get(str(roles), None)
+ exist_creds = self.isolated_creds.get(six.text_type(roles).encode(
+ 'utf-8'), None)
# The force kwarg is used to allocate an additional set of creds with
# the same role list. The index used for the previously allocation
# in the isolated_creds dict will be moved.
if exist_creds and not force_new:
return exist_creds
elif exist_creds and force_new:
- new_index = str(roles) + '-' + str(len(self.isolated_creds))
+ new_index = six.text_type(roles).encode('utf-8') + '-' + \
+ six.text_type(len(self.isolated_creds)).encode('utf-8')
self.isolated_creds[new_index] = exist_creds
net_creds = self._get_creds(roles=roles)
- self.isolated_creds[str(roles)] = net_creds
+ self.isolated_creds[six.text_type(roles).encode('utf-8')] = net_creds
return net_creds
def clear_isolated_creds(self):
@@ -283,8 +286,11 @@
net_clients = clients.Manager(credentials=credential)
compute_network_client = net_clients.networks_client
net_name = self.hash_dict['networks'].get(hash, None)
- network = fixed_network.get_network_from_name(
- net_name, compute_network_client)
+ try:
+ network = fixed_network.get_network_from_name(
+ net_name, compute_network_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
net_creds.set_resources(network=network)
return net_creds
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 298a94e..839088c 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -14,6 +14,7 @@
import re
+import six
from testtools import helpers
@@ -121,7 +122,7 @@
"""
def match(self, actual):
- for key, value in actual.iteritems():
+ for key, value in six.iteritems(actual):
if key in ('content-length', 'x-account-bytes-used',
'x-account-container-count', 'x-account-object-count',
'x-container-bytes-used', 'x-container-object-count')\
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index 1557474..2c6e334 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -17,6 +17,7 @@
from tempest_lib import exceptions as lib_exc
from tempest import config
+from tempest import exceptions
CONF = config.CONF
@@ -29,51 +30,59 @@
:param str name: the name of the network to use
:param NetworksClientJSON compute_networks_client: The network client
object to use for making the network lists api request
- :return: The full dictionary for the network in question, unless the
- network for the supplied name can not be found. In which case a dict
- with just the name will be returned.
+ :return: The full dictionary for the network in question
:rtype: dict
+ :raises InvalidConfiguration: If the name provided is invalid, the networks
+ list returns a 404, there are no found networks, or the found network
+ is invalid
"""
caller = misc_utils.find_test_caller()
+
if not name:
- network = {'name': name}
+ raise exceptions.InvalidConfiguration()
+
+ try:
+ networks = compute_networks_client.list_networks(name=name)
+ except lib_exc.NotFound:
+ # In case of nova network, if the fixed_network_name is not
+ # owned by the tenant, and the network client is not an admin
+ # one, list_networks will not find it
+ msg = ('Unable to find network %s. '
+ 'Starting instance without specifying a network.' %
+ name)
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
+ raise exceptions.InvalidConfiguration()
+
+ # Check that a network exists, else raise an InvalidConfigurationException
+ if len(networks) == 1:
+ network = sorted(networks)[0]
+ elif len(networks) > 1:
+ msg = ("Network with name: %s had multiple matching networks in the "
+ "list response: %s\n Unable to specify a single network" % (
+ name, networks))
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
else:
- try:
- resp = compute_networks_client.list_networks(name=name)
- if isinstance(resp, list):
- networks = resp
- elif isinstance(resp, dict):
- networks = resp['networks']
- else:
- raise lib_exc.NotFound()
- if len(networks) > 0:
- network = networks[0]
- else:
- msg = "Network with name: %s not found" % name
- if caller:
- LOG.warn('(%s) %s' % (caller, msg))
- else:
- LOG.warn(msg)
- raise lib_exc.NotFound()
- # To be consistent with network isolation, add name is only
- # label is available
- name = network.get('name', network.get('label'))
- if name:
- network['name'] = name
- else:
- raise lib_exc.NotFound()
- except lib_exc.NotFound:
- # In case of nova network, if the fixed_network_name is not
- # owned by the tenant, and the network client is not an admin
- # one, list_networks will not find it
- msg = ('Unable to find network %s. '
- 'Starting instance without specifying a network.' %
- name)
- if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
- network = {'name': name}
+ msg = "Network with name: %s not found" % name
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ # To be consistent between neutron and nova network always use name even
+ # if label is used in the api response. If neither is present than then
+ # the returned network is invalid.
+ name = network.get('name') or network.get('label')
+ if not name:
+ msg = "Network found from list doesn't contain a valid name or label"
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ network['name'] = name
return network
@@ -97,16 +106,17 @@
msg = ('No valid network provided or created, defaulting to '
'fixed_network_name')
if caller:
- LOG.debug('(%s) %s' % (caller, msg))
- else:
- LOG.debug(msg)
- network = get_network_from_name(fixed_network_name,
- compute_networks_client)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.debug(msg)
+ try:
+ network = get_network_from_name(fixed_network_name,
+ compute_networks_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
msg = ('Found network %s available for tenant' % network)
if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
return network
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index f81f405..3e09300 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -17,8 +17,8 @@
import functools
import jsonschema
-
from oslo_log import log as logging
+import six
LOG = logging.getLogger(__name__)
@@ -122,7 +122,7 @@
if schema_type == 'object':
properties = schema["properties"]
- for attribute, definition in properties.iteritems():
+ for attribute, definition in six.iteritems(properties):
current_path = copy.copy(path)
if path is not None:
current_path.append(attribute)
diff --git a/tempest/common/generator/valid_generator.py b/tempest/common/generator/valid_generator.py
index 0c63bf5..2213b4a 100644
--- a/tempest/common/generator/valid_generator.py
+++ b/tempest/common/generator/valid_generator.py
@@ -14,6 +14,7 @@
# under the License.
from oslo_log import log as logging
+import six
import tempest.common.generator.base_generator as base
@@ -51,7 +52,7 @@
@base.simple_generator
def generate_valid_object(self, schema):
obj = {}
- for k, v in schema["properties"].iteritems():
+ for k, v in six.iteritems(schema["properties"]):
obj[k] = self.generate_valid(v)
return obj
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
deleted file mode 100644
index d0e484c..0000000
--- a/tempest/common/ssh.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# 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
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import select
-import socket
-import time
-import warnings
-
-from oslo_log import log as logging
-import six
-from six import moves
-
-from tempest import exceptions
-
-
-with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- import paramiko
-
-
-LOG = logging.getLogger(__name__)
-
-
-class Client(object):
-
- def __init__(self, host, username, password=None, timeout=300, pkey=None,
- channel_timeout=10, look_for_keys=False, key_filename=None):
- self.host = host
- self.username = username
- self.password = password
- if isinstance(pkey, six.string_types):
- pkey = paramiko.RSAKey.from_private_key(
- moves.cStringIO(str(pkey)))
- self.pkey = pkey
- self.look_for_keys = look_for_keys
- self.key_filename = key_filename
- self.timeout = int(timeout)
- self.channel_timeout = float(channel_timeout)
- self.buf_size = 1024
-
- def _get_ssh_connection(self, sleep=1.5, backoff=1):
- """Returns an ssh connection to the specified host."""
- bsleep = sleep
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(
- paramiko.AutoAddPolicy())
- _start_time = time.time()
- if self.pkey is not None:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with public key authentication",
- self.host, self.username)
- else:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with password %s",
- self.host, self.username, str(self.password))
- attempts = 0
- while True:
- try:
- ssh.connect(self.host, username=self.username,
- password=self.password,
- look_for_keys=self.look_for_keys,
- key_filename=self.key_filename,
- timeout=self.channel_timeout, pkey=self.pkey)
- LOG.info("ssh connection to %s@%s successfuly created",
- self.username, self.host)
- return ssh
- except (socket.error,
- paramiko.SSHException) as e:
- if self._is_timed_out(_start_time):
- LOG.exception("Failed to establish authenticated ssh"
- " connection to %s@%s after %d attempts",
- self.username, self.host, attempts)
- raise exceptions.SSHTimeout(host=self.host,
- user=self.username,
- password=self.password)
- bsleep += backoff
- attempts += 1
- LOG.warning("Failed to establish authenticated ssh"
- " connection to %s@%s (%s). Number attempts: %s."
- " Retry after %d seconds.",
- self.username, self.host, e, attempts, bsleep)
- time.sleep(bsleep)
-
- def _is_timed_out(self, start_time):
- return (time.time() - self.timeout) > start_time
-
- def exec_command(self, cmd):
- """
- Execute the specified command on the server.
-
- Note that this method is reading whole command outputs to memory, thus
- shouldn't be used for large outputs.
-
- :returns: data read from standard output of the command.
- :raises: SSHExecCommandFailed if command returns nonzero
- status. The exception contains command status stderr content.
- """
- ssh = self._get_ssh_connection()
- transport = ssh.get_transport()
- channel = transport.open_session()
- channel.fileno() # Register event pipe
- channel.exec_command(cmd)
- channel.shutdown_write()
- out_data = []
- err_data = []
- poll = select.poll()
- poll.register(channel, select.POLLIN)
- start_time = time.time()
-
- while True:
- ready = poll.poll(self.channel_timeout)
- if not any(ready):
- if not self._is_timed_out(start_time):
- continue
- raise exceptions.TimeoutException(
- "Command: '{0}' executed on host '{1}'.".format(
- cmd, self.host))
- if not ready[0]: # If there is nothing to read.
- continue
- out_chunk = err_chunk = None
- if channel.recv_ready():
- out_chunk = channel.recv(self.buf_size)
- out_data += out_chunk,
- if channel.recv_stderr_ready():
- err_chunk = channel.recv_stderr(self.buf_size)
- err_data += err_chunk,
- if channel.closed and not err_chunk and not out_chunk:
- break
- exit_status = channel.recv_exit_status()
- if 0 != exit_status:
- raise exceptions.SSHExecCommandFailed(
- command=cmd, exit_status=exit_status,
- strerror=''.join(err_data))
- return ''.join(out_data)
-
- def test_connection_auth(self):
- """Raises an exception when we can not connect to server via ssh."""
- connection = self._get_ssh_connection()
- connection.close()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 29fb493..bedff1f 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -15,8 +15,8 @@
import time
import six
+from tempest_lib.common import ssh
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
diff --git a/tempest/config.py b/tempest/config.py
index 46d2c93..a711b33 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -335,6 +335,13 @@
help="Does the test environment block migration support "
"cinder iSCSI volumes. Note, libvirt doesn't support this, "
"see https://bugs.launchpad.net/nova/+bug/1398999"),
+ # TODO(gilliard): Remove live_migrate_paused_instances at juno-eol.
+ cfg.BoolOpt('live_migrate_paused_instances',
+ default=False,
+ help="Does the test system allow live-migration of paused "
+ "instances? Note, this is more than just the ANDing of "
+ "paused and live_migrate, but all 3 should be set to True "
+ "to run those tests"),
cfg.BoolOpt('vnc_console',
default=False,
help='Enable VNC console. This configuration value should '
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 09f7016..15617c6 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -128,17 +128,6 @@
message = "Got identity error"
-class SSHTimeout(TempestException):
- message = ("Connection to the %(host)s via SSH timed out.\n"
- "User: %(user)s, Password: %(password)s")
-
-
-class SSHExecCommandFailed(TempestException):
- """Raised when remotely executed command returns nonzero status."""
- message = ("Command '%(command)s', exit status: %(exit_status)d, "
- "Error:\n%(strerror)s")
-
-
class ServerUnreachable(TempestException):
message = "The server is not reachable via the configured network"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 98bacf0..7e0c3b3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -381,7 +381,7 @@
def _log_net_info(self, exc):
# network debug is called as part of ssh init
- if not isinstance(exc, exceptions.SSHTimeout):
+ if not isinstance(exc, lib_exc.SSHTimeout):
LOG.debug('Network information on a devstack host')
def create_server_snapshot(self, server, name=None):
@@ -741,7 +741,7 @@
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
try:
- for net_name, ip_addresses in server['addresses'].iteritems():
+ for net_name, ip_addresses in six.iteritems(server['addresses']):
for ip_address in ip_addresses:
self.check_vm_connectivity(ip_address['addr'],
username,
@@ -766,7 +766,7 @@
def ping_remote():
try:
source.ping_host(dest)
- except exceptions.SSHExecCommandFailed:
+ except lib_exc.SSHExecCommandFailed:
LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
% (dest, source.ssh_client.host))
return not should_succeed
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 5aec01f..eb018eb 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import HTMLParser
-import urllib
-import urllib2
+from six.moves import html_parser as HTMLParser
+from six.moves.urllib import parse
+from six.moves.urllib import request
from tempest import config
from tempest.scenario import manager
@@ -68,11 +68,11 @@
super(TestDashboardBasicOps, cls).setup_credentials()
def check_login_page(self):
- response = urllib2.urlopen(CONF.dashboard.dashboard_url)
+ response = request.urlopen(CONF.dashboard.dashboard_url)
self.assertIn("id_username", response.read())
def user_login(self, username, password):
- self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
+ self.opener = request.build_opener(request.HTTPCookieProcessor())
response = self.opener.open(CONF.dashboard.dashboard_url).read()
# Grab the CSRF token and default region
@@ -80,14 +80,14 @@
parser.feed(response)
# Prepare login form request
- req = urllib2.Request(CONF.dashboard.login_url)
+ req = request.Request(CONF.dashboard.login_url)
req.add_header('Content-type', 'application/x-www-form-urlencoded')
req.add_header('Referer', CONF.dashboard.dashboard_url)
params = {'username': username,
'password': password,
'region': parser.region,
'csrfmiddlewaretoken': parser.csrf_token}
- self.opener.open(req, urllib.urlencode(params))
+ self.opener.open(req, parse.urlencode(params))
def check_home_page(self):
response = self.opener.open(CONF.dashboard.dashboard_url)
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 8f37d74..691c7c9 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -16,7 +16,9 @@
import tempfile
import time
-import urllib2
+
+import six
+from six.moves.urllib import request as urllib2
from tempest.common import commands
from tempest import config
@@ -158,7 +160,7 @@
1. SSH to the instance
2. Start two http backends listening on ports 80 and 88 respectively
"""
- for server_id, ip in self.server_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_ips):
private_key = self.servers_keypairs[server_id]['private_key']
server_name = self.servers_client.get_server(server_id)['name']
username = config.scenario.ssh_user
@@ -238,7 +240,7 @@
but with different ports to listen on.
"""
- for server_id, ip in self.server_fixed_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_fixed_ips):
if len(self.server_fixed_ips) == 1:
member1 = self._create_member(address=ip,
protocol_port=self.port1,
@@ -307,7 +309,7 @@
except urllib2.HTTPError:
continue
# Assert that each member of the pool gets balanced at least once
- for member, counter in counters.iteritems():
+ for member, counter in six.iteritems(counters):
self.assertGreater(counter, 0, 'Member %s never balanced' % member)
@test.idempotent_id('c0c6f1ca-603b-4509-9c0f-2c63f0d838ee')
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 16ff848..6e67c4b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -16,6 +16,7 @@
import netaddr
from oslo_log import log as logging
+import six
from tempest import config
from tempest.scenario import manager
@@ -93,7 +94,7 @@
@staticmethod
def define_server_ips(srv):
- for net_name, nics in srv['addresses'].iteritems():
+ for net_name, nics in six.iteritems(srv['addresses']):
for nic in nics:
if nic['version'] == 6:
srv['accessIPv6'] = nic['addr']
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index 6c00d09..60eb1c3 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -23,7 +23,7 @@
import testtools
from tempest import clients
-from tempest.common import cred_provider
+from tempest.common import credentials
from tempest import config
from tempest import exceptions
@@ -41,7 +41,10 @@
self.non_ssh_image_pattern = \
CONF.input_scenario.non_ssh_image_regex
# Setup clients
- os = clients.Manager()
+ self.isolated_creds = credentials.get_isolated_credentials(
+ name='ScenarioImageUtils',
+ identity_version=CONF.identity.auth_version)
+ os = clients.Manager(self.isolated_creds.get_primary_creds())
self.images_client = os.images_client
self.flavors_client = os.flavors_client
@@ -100,8 +103,10 @@
digit=string.digits)
def __init__(self):
- os = clients.Manager(
- cred_provider.get_configured_credentials('user', fill_in=False))
+ self.isolated_creds = credentials.get_isolated_credentials(
+ name='InputScenarioUtils',
+ identity_version=CONF.identity.auth_version)
+ os = clients.Manager(self.isolated_creds.get_primary_creds())
self.images_client = os.images_client
self.flavors_client = os.flavors_client
self.image_pattern = CONF.input_scenario.image_regex
@@ -162,7 +167,7 @@
scenario_utils = InputScenarioUtils()
scenario_flavor = scenario_utils.scenario_flavors
scenario_image = scenario_utils.scenario_images
- except exceptions.InvalidConfiguration:
+ except (exceptions.InvalidConfiguration, TypeError):
return standard_tests
for test in testtools.iterate_tests(standard_tests):
setattr(test, 'scenarios', testscenarios.multiply_scenarios(
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 4c6a5bf..1461198 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -12,9 +12,9 @@
import functools
import json
-import urllib
import six
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 403437d..c69e483 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import agents as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/baremetal_nodes_client.py b/tempest/services/compute/json/baremetal_nodes_client.py
index e4a4e88..fa2d7f4 100644
--- a/tempest/services/compute/json/baremetal_nodes_client.py
+++ b/tempest/services/compute/json/baremetal_nodes_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import baremetal_nodes as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 2de43cf..80cbe4d 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import flavors_access as schema_access
from tempest.api_schema.response.compute import flavors_extra_specs \
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 5bad527..9568a5e 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import floating_ips as schema
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 088e695..287482f 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import hosts as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 1223fef..5462efc 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import images as schema
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index a65b655..009992c 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import migrations as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index d8c8d63..2855e13 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import security_groups as schema
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index c9ba2c3..1af1b37 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -16,8 +16,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import servers as schema
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index fc2274d..e2d959b 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -15,7 +15,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import services as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index ff6e7a2..b7e2b2a 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import tenant_usages as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index ba5921e..4d7a7aa 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import volumes as schema
diff --git a/tempest/services/database/json/limits_client.py b/tempest/services/database/json/limits_client.py
index ae758bc..f99ceaa 100644
--- a/tempest/services/database/json/limits_client.py
+++ b/tempest/services/database/json/limits_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/database/json/versions_client.py b/tempest/services/database/json/versions_client.py
index aa2fef7..0db9c6a 100644
--- a/tempest/services/database/json/versions_client.py
+++ b/tempest/services/database/json/versions_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index bc90fd1..f3d02a8 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/region_client.py b/tempest/services/identity/v3/json/region_client.py
index faaf43c..02df354 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index ec7900b..5e442fa 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -18,9 +18,10 @@
import json
import os
import time
-import urllib
from oslo_log import log as logging
+import six
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc as misc_utils
from tempest_lib import exceptions as lib_exc
@@ -54,7 +55,7 @@
def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
- for key, value in headers.iteritems():
+ for key, value in six.iteritems(headers):
if key.startswith('x-image-meta-property-'):
_key = key[22:]
meta['properties'][_key] = value
@@ -80,11 +81,11 @@
copy_from = fields_copy.pop('copy_from', None)
if copy_from is not None:
headers['x-glance-api-copy-from'] = copy_from
- for key, value in fields_copy.pop('properties', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('properties', {})):
headers['x-image-meta-property-%s' % key] = str(value)
- for key, value in fields_copy.pop('api', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('api', {})):
headers['x-glance-api-property-%s' % key] = str(value)
- for key, value in fields_copy.iteritems():
+ for key, value in six.iteritems(fields_copy):
headers['x-image-meta-%s' % key] = str(value)
return headers
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 6b04144..aff8e85 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -14,9 +14,9 @@
# under the License.
import json
-import urllib
import jsonschema
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import glance_http
diff --git a/tempest/services/messaging/json/messaging_client.py b/tempest/services/messaging/json/messaging_client.py
index 483ba93..5f6c32a 100644
--- a/tempest/services/messaging/json/messaging_client.py
+++ b/tempest/services/messaging/json/messaging_client.py
@@ -14,9 +14,10 @@
# limitations under the License.
import json
-import urllib
import uuid
+from six.moves.urllib import parse as urllib
+
from tempest.api_schema.response.messaging.v1 import queues as queues_schema
from tempest.common import service_client
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 53645a5..e93cc47 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -12,8 +12,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc
from tempest_lib import exceptions as lib_exc
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index af00eff..dece763 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index ed74de4..8e225b0 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 3466c8a..2265587 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,8 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
+import six
from six.moves import http_client as httplib
from six.moves.urllib import parse as urlparse
@@ -36,7 +35,7 @@
headers[str(key)] = metadata[key]
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.put(url, data, headers)
self.expected_success(201, resp.status)
@@ -52,7 +51,7 @@
"""Delete storage object."""
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.delete(url, headers={})
self.expected_success([200, 204], resp.status)
return resp, body
@@ -234,7 +233,7 @@
headers = {}
if hasattr(contents, 'read'):
conn.putrequest('PUT', path)
- for header, value in headers.iteritems():
+ for header, value in six.iteritems(headers):
conn.putheader(header, value)
if 'Content-Length' not in headers:
if 'Transfer-Encoding' not in headers:
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index debf39b..4d443d3 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -16,8 +16,8 @@
import json
import re
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 0c01908..554f574 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,9 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index 1cd92b7..1dfabaf 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 5092afc..cbab3f0 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -12,9 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_services_client.py b/tempest/services/volume/json/admin/volume_services_client.py
index 1c4433f..94792e0 100644
--- a/tempest/services/volume/json/admin/volume_services_client.py
+++ b/tempest/services/volume/json/admin/volume_services_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 9366984..2436d88 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 2140c62..cfa02bd 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -12,9 +12,9 @@
import json
import time
-import urllib
from oslo_log import log as logging
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index a82291a..9a08bbd 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 62e60d6..3f8e537 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -19,12 +19,13 @@
from oslo_log import log as logging
from oslo_utils import importutils
+import six
from six import moves
+from tempest_lib.common import ssh
from tempest_lib.common.utils import data_utils
from tempest import clients
from tempest.common import isolated_creds
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
from tempest.stress import cleanup
@@ -171,7 +172,7 @@
test_run = test_obj(manager, max_runs, stop_on_error)
kwargs = test.get('kwargs', {})
- test_run.setUp(**dict(kwargs.iteritems()))
+ test_run.setUp(**dict(six.iteritems(kwargs)))
LOG.debug("calling Target Object %s" %
test_run.__class__.__name__)
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index f357bf4..87c4bb3 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -20,6 +20,7 @@
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslotest import mockpatch
+import six
from tempest_lib import auth
from tempest_lib.services.identity.v2 import token_client
@@ -79,7 +80,7 @@
hash_list = []
for account in accounts_list:
hash = hashlib.md5()
- hash.update(str(account))
+ hash.update(six.text_type(account).encode('utf-8'))
temp_hash = hash.hexdigest()
hash_list.append(temp_hash)
return hash_list
@@ -265,7 +266,7 @@
'tempest.common.accounts.read_accounts_yaml',
return_value=self.test_accounts))
test_accounts_class = accounts.Accounts('v2', 'test_name')
- hashes = test_accounts_class.hash_dict['creds'].keys()
+ hashes = list(test_accounts_class.hash_dict['creds'].keys())
admin_hashes = test_accounts_class.hash_dict['roles'][
cfg.CONF.identity.admin_role]
temp_hash = hashes[0]
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index 2fa6933..78fd80d 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -17,6 +17,7 @@
import jsonschema
import mock
+import six
from tempest.common.generator import base_generator
from tempest.common.generator import negative_generator
@@ -101,11 +102,11 @@
class fake_test_class(object):
def __init__(self, scenario):
- for k, v in scenario.iteritems():
+ for k, v in six.iteritems(scenario):
setattr(self, k, v)
def _validate_result(self, valid_schema, invalid_schema):
- for k, v in valid_schema.iteritems():
+ for k, v in six.iteritems(valid_schema):
self.assertTrue(k in invalid_schema)
def test_generator_mandatory_functions(self):
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
deleted file mode 100644
index aaacaab..0000000
--- a/tempest/tests/test_ssh.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-#
-# 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
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import contextlib
-import socket
-import time
-
-import mock
-import testtools
-
-from tempest.common import ssh
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestSshClient(base.TestCase):
-
- def test_pkey_calls_paramiko_RSAKey(self):
- with contextlib.nested(
- mock.patch('paramiko.RSAKey.from_private_key'),
- mock.patch('six.moves.cStringIO')) as (rsa_mock, cs_mock):
- cs_mock.return_value = mock.sentinel.csio
- pkey = 'mykey'
- ssh.Client('localhost', 'root', pkey=pkey)
- rsa_mock.assert_called_once_with(mock.sentinel.csio)
- cs_mock.assert_called_once_with('mykey')
- rsa_mock.reset_mock()
- cs_mock.reset_mock()
- pkey = mock.sentinel.pkey
- # Shouldn't call out to load a file from RSAKey, since
- # a sentinel isn't a basestring...
- ssh.Client('localhost', 'root', pkey=pkey)
- self.assertEqual(0, rsa_mock.call_count)
- self.assertEqual(0, cs_mock.call_count)
-
- def _set_ssh_connection_mocks(self):
- client_mock = mock.MagicMock()
- client_mock.connect.return_value = True
- return (self.patch('paramiko.SSHClient'),
- self.patch('paramiko.AutoAddPolicy'),
- client_mock)
-
- def test_get_ssh_connection(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
- s_mock = self.patch('time.sleep')
-
- c_mock.return_value = client_mock
- aa_mock.return_value = mock.sentinel.aa
-
- # Test normal case for successful connection on first try
- client = ssh.Client('localhost', 'root', timeout=2)
- client._get_ssh_connection(sleep=1)
-
- aa_mock.assert_called_once_with()
- client_mock.set_missing_host_key_policy.assert_called_once_with(
- mock.sentinel.aa)
- expected_connect = [mock.call(
- 'localhost',
- username='root',
- pkey=None,
- key_filename=None,
- look_for_keys=False,
- timeout=10.0,
- password=None
- )]
- self.assertEqual(expected_connect, client_mock.connect.mock_calls)
- self.assertEqual(0, s_mock.call_count)
-
- def test_get_ssh_connection_two_attemps(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- mock.MagicMock()
- ]
-
- client = ssh.Client('localhost', 'root', timeout=1)
- start_time = int(time.time())
- client._get_ssh_connection(sleep=1)
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 4)
- self.assertGreater((end_time - start_time), 1)
-
- def test_get_ssh_connection_timeout(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- socket.error,
- socket.error,
- ]
-
- client = ssh.Client('localhost', 'root', timeout=2)
- start_time = int(time.time())
- with testtools.ExpectedException(exceptions.SSHTimeout):
- client._get_ssh_connection()
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 5)
- self.assertGreaterEqual((end_time - start_time), 2)
-
- def test_exec_command(self):
- gsc_mock = self.patch('tempest.common.ssh.Client._get_ssh_connection')
- ito_mock = self.patch('tempest.common.ssh.Client._is_timed_out')
- select_mock = self.patch('select.poll')
-
- client_mock = mock.MagicMock()
- tran_mock = mock.MagicMock()
- chan_mock = mock.MagicMock()
- poll_mock = mock.MagicMock()
-
- def reset_mocks():
- gsc_mock.reset_mock()
- ito_mock.reset_mock()
- select_mock.reset_mock()
- poll_mock.reset_mock()
- client_mock.reset_mock()
- tran_mock.reset_mock()
- chan_mock.reset_mock()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = True
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [0, 0, 0]
- ]
-
- # Test for a timeout condition immediately raised
- client = ssh.Client('localhost', 'root', timeout=2)
- with testtools.ExpectedException(exceptions.TimeoutException):
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
-
- # Test for proper reading of STDOUT and STDERROR and closing
- # of all file descriptors.
-
- reset_mocks()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = False
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [1, 0, 0]
- ]
- closed_prop = mock.PropertyMock(return_value=True)
- type(chan_mock).closed = closed_prop
- chan_mock.recv_exit_status.return_value = 0
- chan_mock.recv.return_value = ''
- chan_mock.recv_stderr.return_value = ''
-
- client = ssh.Client('localhost', 'root', timeout=2)
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
- chan_mock.recv_ready.assert_called_once_with()
- chan_mock.recv.assert_called_once_with(1024)
- chan_mock.recv_stderr_ready.assert_called_once_with()
- chan_mock.recv_stderr.assert_called_once_with(1024)
- chan_mock.recv_exit_status.assert_called_once_with()
- closed_prop.assert_called_once_with()