Merge "Add new base manager with default network" into mcp/caracal
diff --git a/tempest/api/compute/admin/test_volume.py b/tempest/api/compute/admin/test_volume.py
index dc631e5..b0f20f6 100644
--- a/tempest/api/compute/admin/test_volume.py
+++ b/tempest/api/compute/admin/test_volume.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
from tempest.common import waiters
from tempest import config
@@ -41,6 +43,9 @@
class AttachSCSIVolumeTestJSON(BaseAttachSCSIVolumeTest):
"""Test attaching scsi volume to server"""
+ @testtools.skipIf(
+ CONF.compute_feature_enabled.barbican_integration_enabled,
+ "Not supported when barbican integration enabled.")
@decorators.idempotent_id('777e468f-17ca-4da4-b93d-b7dbf56c0494')
def test_attach_scsi_disk_with_config_drive(self):
"""Test the attach/detach volume with config drive/scsi disk
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 8984d1d..688b31b 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -109,21 +109,24 @@
"""
port = self.ports_client.show_port(port_id)['port']
device_id = port['device_id']
+ dns_name = port.get('dns_name')
start = int(time.time())
# NOTE(mriedem): Nova updates the port's device_id to '' rather than
# None, but it's not contractual so handle Falsey either way.
- while device_id:
+ while any([device_id, dns_name]):
time.sleep(self.build_interval)
port = self.ports_client.show_port(port_id)['port']
device_id = port['device_id']
+ dns_name = port.get('dns_name')
timed_out = int(time.time()) - start >= self.build_timeout
- if device_id and timed_out:
- message = ('Port %s failed to detach (device_id %s) within '
- 'the required time (%s s).' %
- (port_id, device_id, self.build_timeout))
+ if any([device_id, dns_name]) and timed_out:
+ message = ('Port %s failed to detach (device_id %s), '
+ '(dns_name %s) within the required time (%s s).' %
+ (port_id, device_id or 'is out',
+ dns_name or 'is out', self.build_timeout))
raise lib_exc.TimeoutException(message)
return port
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 1308b19..c90aea8 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -64,7 +64,15 @@
def _validate_novnc_html(self, vnc_url):
"""Verify we can connect to novnc and get back the javascript."""
- resp = urllib3.PoolManager().request('GET', vnc_url)
+ cert_params = {}
+
+ if CONF.identity.disable_ssl_certificate_validation:
+ cert_params['cert_reqs'] = "CERT_NONE"
+ else:
+ cert_params["cert_reqs"] = "CERT_REQUIRED"
+ cert_params["ca_certs"] = CONF.identity.ca_certificates_file
+
+ resp = urllib3.PoolManager(**cert_params).request('GET', vnc_url)
# Make sure that the GET request was accepted by the novncproxy
self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the '
'initial call: ' + str(resp.status))
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index 38ca53b..286e0a5 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -13,10 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
from tempest.common import tempest_fixtures as fixtures
+from tempest import config
from tempest.lib import decorators
+CONF = config.CONF
+
class QuotasTestJSON(base.BaseV2ComputeTest):
"""Test compute quotas"""
@@ -76,6 +81,8 @@
for quota in expected_quota_set:
self.assertIn(quota, quota_set.keys())
+ @testtools.skipIf(not CONF.auth.use_dynamic_credentials,
+ 'does not support static credentials')
@decorators.idempotent_id('cd65d997-f7e4-4966-a7e9-d5001b674fdc')
def test_compare_tenant_quotas_with_default_quotas(self):
"""Test tenants are created with the default compute quota values"""
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index 689844b..f398062 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -45,6 +45,9 @@
if not utils.is_extension_enabled('subnet_allocation', 'network'):
msg = "subnet_allocation extension not enabled."
raise cls.skipException(msg)
+ if not utils.is_extension_enabled('default-subnetpools', 'network'):
+ msg = "default-subnetpools extension not enabled."
+ raise cls.skipException(msg)
@decorators.attr(type='smoke')
@decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811')
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index f055d19..d4bf0d7 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -88,9 +88,12 @@
nafter = self._get_bytes_used()
self.assertEqual(nbefore, nafter)
+ # NOTE(vsaienko): the quotas imlementation on active/active rgw deployment
+ # have no coordination, as result quota overflow might happen, since
+ # this is upstream and we can't fix downstream. Remove test from smoke
+ # Related-Prod: PRODX-11581
@decorators.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b')
@utils.requires_ext(extension='container_quotas', service='object')
- @decorators.attr(type="smoke")
def test_upload_too_many_objects(self):
"""Attempts to upload many objects that exceeds the count limit."""
for _ in range(QUOTA_COUNT):
diff --git a/tempest/api/volume/admin/test_volume_retype.py b/tempest/api/volume/admin/test_volume_retype.py
index 7c25f3d..4cb2262 100644
--- a/tempest/api/volume/admin/test_volume_retype.py
+++ b/tempest/api/volume/admin/test_volume_retype.py
@@ -179,10 +179,11 @@
keys_with_change = ('volume_type',)
# NOTE(vsaienko): with active-active cluster deployment volume
- # services registered with different hostname.
- if CONF.volume_feature_enabled.cluster_active_active:
- keys_with_change += ('os-vol-host-attr:host',)
- else:
+ # services registered with different hostname since we don't know
+ # which service process request host might or might not be changed.
+ # TODO(vsaienko): Revisit logic when is fixed
+ # https://bugs.launchpad.net/cinder/+bug/1874414
+ if not CONF.volume_feature_enabled.cluster_active_active:
keys_with_no_change += ('os-vol-host-attr:host',)
# Check the volume information after the retype
diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py
index ba3d787..5d1f315 100644
--- a/tempest/lib/api_schema/response/compute/v2_19/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_19/servers.py
@@ -14,9 +14,12 @@
import copy
+from tempest.lib.api_schema.response.compute.v2_1 import servers \
+ as servers
from tempest.lib.api_schema.response.compute.v2_16 import servers \
as serversv216
+
# Compute microversion 2.19:
# 1. New attributes in 'server' dict.
# 'description'
@@ -63,3 +66,4 @@
list_volume_attachments = copy.deepcopy(serversv216.list_volume_attachments)
show_instance_action = copy.deepcopy(serversv216.show_instance_action)
create_backup = copy.deepcopy(serversv216.create_backup)
+list_instance_actions = copy.deepcopy(servers.list_instance_actions)
diff --git a/tempest/lib/api_schema/response/compute/v2_58/servers.py b/tempest/lib/api_schema/response/compute/v2_58/servers.py
index 637b765..5c22c79 100644
--- a/tempest/lib/api_schema/response/compute/v2_58/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_58/servers.py
@@ -12,8 +12,10 @@
import copy
from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.compute.v2_1 import servers as servers
from tempest.lib.api_schema.response.compute.v2_57 import servers as servers257
+
# microversion 2.58 added updated_at to the response
show_instance_action = copy.deepcopy(servers257.show_instance_action)
show_instance_action['response_body']['properties']['instanceAction'][
@@ -21,6 +23,14 @@
show_instance_action['response_body']['properties']['instanceAction'][
'required'].append('updated_at')
+# microversion 2.58 added updated_at to the response
+list_instance_actions = copy.deepcopy(servers.list_instance_actions)
+list_instance_actions['response_body']['properties']['instanceActions'][
+ 'items']['properties'].update({'updated_at': parameter_types.date_time})
+list_instance_actions['response_body']['properties']['instanceActions'][
+ 'items']['required'].append('updated_at')
+
+
# Below are the unchanged schema in this microversion. We need
# to keep this schema in this file to have the generic way to select the
# right schema based on self.schema_versions_info mapping in service client.
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index a2f2931..4e1dc59 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -94,6 +94,7 @@
self.build_interval = build_interval
self.build_timeout = build_timeout
self.trace_requests = trace_requests
+ self.ca_certs = ca_certs
self._skip_path = False
self.general_header_lc = set(('cache-control', 'connection',
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index 662b452..bdf35e7 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -31,35 +31,33 @@
return function(self, *args, **kwargs)
except Exception as e:
caller = test_utils.find_test_caller() or "not found"
- if not isinstance(e, tempest.lib.exceptions.SSHTimeout):
- message = ('Executing command on %(ip)s failed. '
- 'Error: %(error)s' % {'ip': self.ip_address,
- 'error': e})
- message = '(%s) %s' % (caller, message)
- LOG.error(message)
- raise
- else:
- try:
- original_exception = sys.exc_info()
- if self.server:
+ message = ('Executing command on %(ip)s failed. '
+ 'Error: %(error)s' % {'ip': self.ip_address,
+ 'error': e})
+ message = '(%s) %s' % (caller, message)
+ LOG.error(message)
+ try:
+ original_exception = sys.exc_info()
+ if self.server:
+ if isinstance(e, tempest.lib.exceptions.SSHTimeout):
msg = 'Caller: %s. Timeout trying to ssh to server %s'
LOG.debug(msg, caller, self.server)
- if self.console_output_enabled and self.servers_client:
- try:
- msg = 'Console log for server %s: %s'
- console_log = (
- self.servers_client.get_console_output(
- self.server['id'])['output'])
- LOG.debug(msg, self.server['id'], console_log)
- except Exception:
- msg = 'Could not get console_log for server %s'
- LOG.debug(msg, self.server['id'])
- # raise the original ssh timeout exception
- raise
- finally:
- # Delete the traceback to avoid circular references
- _, _, trace = original_exception
- del trace
+ if self.console_output_enabled and self.servers_client:
+ try:
+ msg = 'Console log for server %s: %s'
+ console_log = (
+ self.servers_client.get_console_output(
+ self.server['id'])['output'])
+ LOG.debug(msg, self.server['id'], console_log)
+ except Exception:
+ msg = 'Could not get console_log for server %s'
+ LOG.debug(msg, self.server['id'])
+ # raise the original ssh exception
+ raise
+ finally:
+ # Delete the traceback to avoid circular references
+ _, _, trace = original_exception
+ del trace
return wrapper
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 58008aa..274e62d 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -721,6 +721,8 @@
resp, body = self.get("servers/%s/os-instance-actions" %
server_id)
body = json.loads(body)
+ # select proper schema depending on microverion
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_instance_actions, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/object_storage/object_client.py b/tempest/lib/services/object_storage/object_client.py
index 65e8227..c7ac80f 100644
--- a/tempest/lib/services/object_storage/object_client.py
+++ b/tempest/lib/services/object_storage/object_client.py
@@ -167,11 +167,14 @@
:param parsed_url: parsed url of the remote location
"""
context = None
- # If CONF.identity.disable_ssl_certificate_validation is true,
- # do not check ssl certification.
- if self.dscv:
- context = ssl._create_unverified_context()
if parsed_url.scheme == 'https':
+ # If CONF.identity.disable_ssl_certificate_validation is true,
+ # do not check ssl certification.
+ if self.dscv:
+ context = ssl._create_unverified_context()
+ else:
+ context = ssl.create_default_context(
+ cafile=self.ca_certs)
conn = httplib.HTTPSConnection(parsed_url.netloc,
context=context)
else:
diff --git a/tempest/serial_tests/api/admin/test_aggregates.py b/tempest/serial_tests/api/admin/test_aggregates.py
index cedeec0..ce54957 100644
--- a/tempest/serial_tests/api/admin/test_aggregates.py
+++ b/tempest/serial_tests/api/admin/test_aggregates.py
@@ -222,6 +222,9 @@
@decorators.idempotent_id('96be03c7-570d-409c-90f8-e4db3c646996')
def test_aggregate_add_host_create_server_with_az(self):
"""Test adding a host to the given aggregate and creating a server"""
+ if CONF.production:
+ raise self.skipException("Not allowed to run this test "
+ "on production environment")
self.useFixture(fixtures.LockFixture('availability_zone'))
az_name = data_utils.rand_name(
prefix=CONF.resource_name_prefix, name=self.az_name_prefix)
@@ -235,12 +238,20 @@
if agg['availability_zone']:
hosts_in_zone.extend(agg['hosts'])
hosts = [v for v in self.hosts_available if v not in hosts_in_zone]
- if not hosts:
+ hosts_available = []
+ for host in hosts:
+ hypervisor_servers = (
+ self.os_admin.hypervisor_client.list_servers_on_hypervisor(
+ host)["hypervisors"][0].get("servers", None))
+ if not hypervisor_servers:
+ hosts_available.append(host)
+ if not hosts_available:
raise self.skipException("All hosts are already in other "
- "availability zones, so can't add "
+ "availability zones or have running "
+ "instances, so can't add "
"host to aggregate. \nAggregates list: "
"%s" % aggregates)
- host = hosts[0]
+ host = hosts_available[0]
self.client.add_host(aggregate['id'], host=host)
self.addCleanup(self.client.remove_host, aggregate['id'], host=host)
diff --git a/tempest/serial_tests/scenario/test_aggregates_basic_ops.py b/tempest/serial_tests/scenario/test_aggregates_basic_ops.py
index a831fe5..cc45297 100644
--- a/tempest/serial_tests/scenario/test_aggregates_basic_ops.py
+++ b/tempest/serial_tests/scenario/test_aggregates_basic_ops.py
@@ -63,7 +63,11 @@
hosts_available = []
for host in svc_list:
if (host['state'] == 'up' and host['status'] == 'enabled'):
- hosts_available.append(host['host'])
+ hypervisor_servers = (
+ self.os_admin.hypervisor_client.list_servers_on_hypervisor(
+ host["host"])["hypervisors"][0].get("servers", None))
+ if not hypervisor_servers:
+ hosts_available.append(host["host"])
aggregates = self.aggregates_client.list_aggregates()['aggregates']
hosts_in_zone = []
for agg in aggregates:
@@ -72,7 +76,8 @@
hosts = [v for v in hosts_available if v not in hosts_in_zone]
if not hosts:
raise self.skipException("All hosts are already in other "
- "availability zones, so can't add "
+ "availability zones or have running "
+ "instances, so can't add "
"host to aggregate. \nAggregates list: "
"%s" % aggregates)
return hosts[0]
@@ -120,6 +125,9 @@
@decorators.attr(type='slow')
@utils.services('compute')
def test_aggregate_basic_ops(self):
+ if CONF.production:
+ raise self.skipException("Not allowed to run this test "
+ "on production environment")
self.useFixture(fixtures.LockFixture('availability_zone'))
az = 'foo_zone'
aggregate_name = data_utils.rand_name(
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 937f93a..5801f04 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -180,9 +180,7 @@
def test_validate_debug_ssh_console(self):
self.assertRaises(lib_exc.SSHTimeout,
self.conn.validate_authentication)
- msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
- 'TestRemoteClientWithServer:test_validate_debug_ssh_console',
- self.server)
+ msg = 'Executing command on 127.0.0.1 failed.'
self.assertIn(msg, self.log.output)
self.assertIn('Console output for', self.log.output)
@@ -190,9 +188,7 @@
self.assertRaises(lib_exc.SSHTimeout,
self.conn.exec_command, 'fake command')
self.assertIn('fake command', self.log.output)
- msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
- 'TestRemoteClientWithServer:test_exec_command_debug_ssh_console',
- self.server)
+ msg = 'Executing command on 127.0.0.1 failed.'
self.assertIn(msg, self.log.output)
self.assertIn('Console output for', self.log.output)
@@ -204,9 +200,7 @@
def test_validate_debug_ssh_console(self):
self.assertRaises(lib_exc.SSHTimeout,
self.conn.validate_authentication)
- msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
- 'TestRemoteClientWithBrokenServer:test_validate_debug_ssh_console',
- self.server)
+ msg = 'Executing command on 127.0.0.1 failed.'
self.assertIn(msg, self.log.output)
msg = 'Could not get console_log for server %s' % self.server['id']
self.assertIn(msg, self.log.output)
@@ -215,10 +209,7 @@
self.assertRaises(lib_exc.SSHTimeout,
self.conn.exec_command, 'fake command')
self.assertIn('fake command', self.log.output)
- caller = ":".join(['TestRemoteClientWithBrokenServer',
- 'test_exec_command_debug_ssh_console'])
- msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
- caller, self.server)
+ msg = 'Executing command on 127.0.0.1 failed.'
self.assertIn(msg, self.log.output)
msg = 'Could not get console_log for server %s' % self.server['id']
self.assertIn(msg, self.log.output)
diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py
index df23e63..c41f178 100644
--- a/tempest/tests/lib/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/lib/common/utils/linux/test_remote_client.py
@@ -15,6 +15,8 @@
from unittest import mock
+import fixtures
+
from tempest.lib.common import ssh
from tempest.lib.common.utils.linux import remote_client
from tempest.lib import exceptions as lib_exc
@@ -29,6 +31,12 @@
class TestRemoteClient(base.TestCase):
+ def setUp(self):
+ super(TestRemoteClient, self).setUp()
+ self.log = self.useFixture(fixtures.FakeLogger(
+ name='tempest.lib.common.utils.linux.remote_client',
+ level='DEBUG'))
+
@mock.patch.object(ssh.Client, 'exec_command', return_value='success')
def test_exec_command(self, mock_ssh_exec_command):
client = remote_client.RemoteClient('192.168.1.10', 'username')
@@ -50,9 +58,8 @@
client = remote_client.RemoteClient('192.168.1.10', 'username',
server=server)
self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls')
- mock_debug.assert_called_with(
- 'Caller: %s. Timeout trying to ssh to server %s',
- 'TestRemoteClient:test_debug_ssh_without_console', server)
+ msg = 'Executing command on 192.168.1.10 failed.'
+ self.assertIn(msg, self.log.output)
@mock.patch.object(remote_client.LOG, 'debug')
@mock.patch.object(ssh.Client, 'exec_command')