Merge "Verify top key in _parse_body"
diff --git a/tempest/lib/api_schema/response/volume/v3_61/__init__.py b/tempest/lib/api_schema/response/volume/v3_61/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_61/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/v3_61/volumes.py b/tempest/lib/api_schema/response/volume/v3_61/volumes.py
new file mode 100644
index 0000000..2e28b7e
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_61/volumes.py
@@ -0,0 +1,69 @@
+# Copyright 2022 Red Hat, Inc.
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.volume import volumes
+
+# Volume micro version 3.61:
+# 1. Add cluster_name attribute to response body of volume details
+# for admin in Active/Active HA mode.
+# https://docs.openstack.org/cinder/latest/contributor/
+# api_microversion_history.html
+
+common_show_volume = copy.deepcopy(volumes.common_show_volume)
+common_show_volume['properties'].update(
+ {'cluster_name': parameter_types.uuid_or_null})
+
+create_volume = copy.deepcopy(volumes.create_volume)
+create_volume['response_body']['properties']['volume']['properties'].update(
+ {'cluster_name': parameter_types.uuid_or_null})
+
+# copy unchanged volumes schema
+attachments = copy.deepcopy(volumes.attachments)
+list_volumes_no_detail = copy.deepcopy(volumes.list_volumes_no_detail)
+# show_volume refers to common_show_volume
+show_volume = copy.deepcopy(volumes.show_volume)
+show_volume['response_body']['properties']['volume'] = common_show_volume
+# list copy refers to latest common_show_volume
+list_volumes_detail = copy.deepcopy(common_show_volume)
+list_volumes_with_detail = copy.deepcopy(volumes.list_volumes_with_detail)
+list_volumes_with_detail['response_body']['properties']['volumes']['items'] \
+ = list_volumes_detail
+update_volume = copy.deepcopy(volumes.update_volume)
+delete_volume = copy.deepcopy(volumes.delete_volume)
+show_volume_summary = copy.deepcopy(volumes.show_volume_summary)
+attach_volume = copy.deepcopy(volumes.attach_volume)
+set_bootable_volume = copy.deepcopy(volumes.set_bootable_volume)
+detach_volume = copy.deepcopy(volumes.detach_volume)
+reserve_volume = copy.deepcopy(volumes.reserve_volume)
+unreserve_volume = copy.deepcopy(volumes.unreserve_volume)
+extend_volume = copy.deepcopy(volumes.extend_volume)
+reset_volume_status = copy.deepcopy(volumes.reset_volume_status)
+update_volume_readonly = copy.deepcopy(volumes.update_volume_readonly)
+force_delete_volume = copy.deepcopy(volumes.force_delete_volume)
+retype_volume = copy.deepcopy(volumes.retype_volume)
+force_detach_volume = copy.deepcopy(volumes.force_detach_volume)
+create_volume_metadata = copy.deepcopy(volumes.create_volume_metadata)
+show_volume_metadata = copy.deepcopy(volumes.show_volume_metadata)
+update_volume_metadata = copy.deepcopy(volumes.update_volume_metadata)
+update_volume_metadata_item = copy.deepcopy(
+ volumes.update_volume_metadata_item)
+update_volume_image_metadata = copy.deepcopy(
+ volumes.update_volume_image_metadata)
+delete_volume_image_metadata = copy.deepcopy(
+ volumes.delete_volume_image_metadata)
+unmanage_volume = copy.deepcopy(volumes.unmanage_volume)
diff --git a/tempest/lib/api_schema/response/volume/v3_63/__init__.py b/tempest/lib/api_schema/response/volume/v3_63/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_63/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/v3_63/volumes.py b/tempest/lib/api_schema/response/volume/v3_63/volumes.py
new file mode 100644
index 0000000..218db90
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_63/volumes.py
@@ -0,0 +1,69 @@
+# Copyright 2022 Red Hat, Inc.
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.volume.v3_61 import volumes
+
+# Volume micro version 3.63:
+# 1. Includes volume type ID in the volume-show and volume-detail-list.
+# for admin in Active/Active HA mode.
+# https://docs.openstack.org/cinder/latest/contributor/
+# api_microversion_history.html
+
+common_show_volume = copy.deepcopy(volumes.common_show_volume)
+common_show_volume['properties'].update(
+ {'volume_type_id': parameter_types.uuid_or_null})
+
+create_volume = copy.deepcopy(volumes.create_volume)
+create_volume['response_body']['properties']['volume']['properties'].update(
+ {'volume_type_id': parameter_types.uuid_or_null})
+
+# copy unchanged volumes schema
+attachments = copy.deepcopy(volumes.attachments)
+list_volumes_no_detail = copy.deepcopy(volumes.list_volumes_no_detail)
+# show_volume refers to common_show_volume
+show_volume = copy.deepcopy(volumes.show_volume)
+show_volume['response_body']['properties']['volume'] = common_show_volume
+# list copy refers to latest common_show_volume
+list_volumes_detail = copy.deepcopy(common_show_volume)
+list_volumes_with_detail = copy.deepcopy(volumes.list_volumes_with_detail)
+list_volumes_with_detail['response_body']['properties']['volumes']['items'] \
+ = list_volumes_detail
+update_volume = copy.deepcopy(volumes.update_volume)
+delete_volume = copy.deepcopy(volumes.delete_volume)
+show_volume_summary = copy.deepcopy(volumes.show_volume_summary)
+attach_volume = copy.deepcopy(volumes.attach_volume)
+set_bootable_volume = copy.deepcopy(volumes.set_bootable_volume)
+detach_volume = copy.deepcopy(volumes.detach_volume)
+reserve_volume = copy.deepcopy(volumes.reserve_volume)
+unreserve_volume = copy.deepcopy(volumes.unreserve_volume)
+extend_volume = copy.deepcopy(volumes.extend_volume)
+reset_volume_status = copy.deepcopy(volumes.reset_volume_status)
+update_volume_readonly = copy.deepcopy(volumes.update_volume_readonly)
+force_delete_volume = copy.deepcopy(volumes.force_delete_volume)
+retype_volume = copy.deepcopy(volumes.retype_volume)
+force_detach_volume = copy.deepcopy(volumes.force_detach_volume)
+create_volume_metadata = copy.deepcopy(volumes.create_volume_metadata)
+show_volume_metadata = copy.deepcopy(volumes.show_volume_metadata)
+update_volume_metadata = copy.deepcopy(volumes.update_volume_metadata)
+update_volume_metadata_item = copy.deepcopy(
+ volumes.update_volume_metadata_item)
+update_volume_image_metadata = copy.deepcopy(
+ volumes.update_volume_image_metadata)
+delete_volume_image_metadata = copy.deepcopy(
+ volumes.delete_volume_image_metadata)
+unmanage_volume = copy.deepcopy(volumes.unmanage_volume)
diff --git a/tempest/lib/api_schema/response/volume/v3_64/__init__.py b/tempest/lib/api_schema/response/volume/v3_64/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_64/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/v3_64/backups.py b/tempest/lib/api_schema/response/volume/v3_64/backups.py
new file mode 100644
index 0000000..01b93bc
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_64/backups.py
@@ -0,0 +1,48 @@
+# Copyright 2022 Red Hat, Inc.
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.volume import backups
+
+# Volume micro version 3.64:
+# 1. Include the encryption_key_id in volume and backup
+# details when the associated volume is encrypted.
+# https://docs.openstack.org/cinder/latest/contributor/
+# api_microversion_history.html
+
+common_show_backup = copy.deepcopy(backups.common_show_backup)
+common_show_backup['properties'].update(
+ {'encryption_key_id': parameter_types.uuid_or_null})
+
+create_backup = copy.deepcopy(backups.create_backup)
+update_backup = copy.deepcopy(backups.update_backup)
+restore_backup = copy.deepcopy(backups.restore_backup)
+delete_backup = copy.deepcopy(backups.delete_backup)
+# show backup refers to common_show_backup
+show_backup = copy.deepcopy(backups.show_backup)
+show_backup['response_body']['properties']['backup'] = common_show_backup
+list_backups_no_detail = copy.deepcopy(backups.list_backups_no_detail)
+# list_backups_detail refers to latest common_show_backup
+list_backups_detail = copy.deepcopy(common_show_backup)
+list_backups_detail['properties'].update({'count': {'type': 'integer'}})
+list_backups_with_detail = copy.deepcopy(backups.list_backups_with_detail)
+# list_backups_with_detail refers to latest list_backups_detail
+list_backups_with_detail['response_body']['properties']['backups']['items'] =\
+ list_backups_detail
+export_backup = copy.deepcopy(backups.export_backup)
+import_backup = copy.deepcopy(backups.import_backup)
+reset_backup_status = copy.deepcopy(backups.reset_backup_status)
diff --git a/tempest/lib/api_schema/response/volume/v3_64/volumes.py b/tempest/lib/api_schema/response/volume/v3_64/volumes.py
new file mode 100644
index 0000000..0fbbb3f
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_64/volumes.py
@@ -0,0 +1,69 @@
+# Copyright 2022 Red Hat, Inc.
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.volume.v3_63 import volumes
+
+# Volume micro version 3.64:
+# 1. Include the encryption_key_id in volume and backup
+# details when the associated volume is encrypted.
+# https://docs.openstack.org/cinder/latest/contributor/
+# api_microversion_history.html
+
+common_show_volume = copy.deepcopy(volumes.common_show_volume)
+common_show_volume['properties'].update(
+ {'encryption_key_id': parameter_types.uuid_or_null})
+
+create_volume = copy.deepcopy(volumes.create_volume)
+create_volume['response_body']['properties']['volume']['properties'].update(
+ {'encryption_key_id': parameter_types.uuid_or_null})
+
+# copy unchanged volumes schema
+attachments = copy.deepcopy(volumes.attachments)
+list_volumes_no_detail = copy.deepcopy(volumes.list_volumes_no_detail)
+# show_volume refers to common_show_volume
+show_volume = copy.deepcopy(volumes.show_volume)
+show_volume['response_body']['properties']['volume'] = common_show_volume
+# list_volumes_detail refers to latest common_show_volume
+list_volumes_detail = copy.deepcopy(common_show_volume)
+list_volumes_with_detail = copy.deepcopy(volumes.list_volumes_with_detail)
+list_volumes_with_detail['response_body']['properties']['volumes']['items'] \
+ = list_volumes_detail
+update_volume = copy.deepcopy(volumes.update_volume)
+delete_volume = copy.deepcopy(volumes.delete_volume)
+show_volume_summary = copy.deepcopy(volumes.show_volume_summary)
+attach_volume = copy.deepcopy(volumes.attach_volume)
+set_bootable_volume = copy.deepcopy(volumes.set_bootable_volume)
+detach_volume = copy.deepcopy(volumes.detach_volume)
+reserve_volume = copy.deepcopy(volumes.reserve_volume)
+unreserve_volume = copy.deepcopy(volumes.unreserve_volume)
+extend_volume = copy.deepcopy(volumes.extend_volume)
+reset_volume_status = copy.deepcopy(volumes.reset_volume_status)
+update_volume_readonly = copy.deepcopy(volumes.update_volume_readonly)
+force_delete_volume = copy.deepcopy(volumes.force_delete_volume)
+retype_volume = copy.deepcopy(volumes.retype_volume)
+force_detach_volume = copy.deepcopy(volumes.force_detach_volume)
+create_volume_metadata = copy.deepcopy(volumes.create_volume_metadata)
+show_volume_metadata = copy.deepcopy(volumes.show_volume_metadata)
+update_volume_metadata = copy.deepcopy(volumes.update_volume_metadata)
+update_volume_metadata_item = copy.deepcopy(
+ volumes.update_volume_metadata_item)
+update_volume_image_metadata = copy.deepcopy(
+ volumes.update_volume_image_metadata)
+delete_volume_image_metadata = copy.deepcopy(
+ volumes.delete_volume_image_metadata)
+unmanage_volume = copy.deepcopy(volumes.unmanage_volume)
diff --git a/tempest/lib/services/volume/v3/backups_client.py b/tempest/lib/services/volume/v3/backups_client.py
index 4bf7ffb..0c32c52 100644
--- a/tempest/lib/services/volume/v3/backups_client.py
+++ b/tempest/lib/services/volume/v3/backups_client.py
@@ -18,6 +18,7 @@
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.volume import backups as schema
+from tempest.lib.api_schema.response.volume.v3_64 import backups as schemav364
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.volume import base_client
@@ -26,6 +27,11 @@
class BackupsClient(base_client.BaseClient):
"""Volume V3 Backups client"""
+ schema_versions_info = [
+ {'min': None, 'max': '3.63', 'schema': schema},
+ {'min': '3.64', 'max': None, 'schema': schemav364}
+ ]
+
def create_backup(self, **kwargs):
"""Creates a backup of volume.
@@ -76,6 +82,7 @@
url = "backups/%s" % backup_id
resp, body = self.get(url)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.show_backup, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -88,6 +95,7 @@
https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-backups-with-detail
"""
url = "backups"
+ schema = self.get_schema(self.schema_versions_info)
list_backups_schema = schema.list_backups_no_detail
if detail:
url += "/detail"
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index 9c6fe68..9934e47 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -17,6 +17,9 @@
from oslo_serialization import jsonutils as json
+from tempest.lib.api_schema.response.volume.v3_61 import volumes as schemav361
+from tempest.lib.api_schema.response.volume.v3_63 import volumes as schemav363
+from tempest.lib.api_schema.response.volume.v3_64 import volumes as schemav364
from tempest.lib.api_schema.response.volume import volumes as schema
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
@@ -26,6 +29,13 @@
class VolumesClient(base_client.BaseClient):
"""Client class to send CRUD Volume V3 API requests"""
+ schema_versions_info = [
+ {'min': None, 'max': '3.60', 'schema': schema},
+ {'min': '3.61', 'max': '3.62', 'schema': schemav361},
+ {'min': '3.63', 'max': '3.63', 'schema': schemav363},
+ {'min': '3.64', 'max': None, 'schema': schemav364}
+ ]
+
def _prepare_params(self, params):
"""Prepares params for use in get or _ext_get methods.
@@ -56,6 +66,7 @@
https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes
"""
url = 'volumes'
+ schema = self.get_schema(self.schema_versions_info)
list_schema = schema.list_volumes_no_detail
if detail:
list_schema = schema.list_volumes_with_detail
@@ -86,6 +97,7 @@
url = "volumes/%s" % volume_id
resp, body = self.get(url)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.show_volume, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -99,6 +111,7 @@
post_body = json.dumps({'volume': kwargs})
resp, body = self.post('volumes', post_body)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_volume, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index ce45ff6..73ce08f 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -477,7 +477,8 @@
self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
snapshot['id'])
- self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.snapshots_client.delete_snapshot, snapshot['id'])
waiters.wait_for_volume_resource_status(self.snapshots_client,
snapshot['id'], 'available')
snapshot = self.snapshots_client.show_snapshot(
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 5aac19c..8cafd1f 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.common import custom_matchers
from tempest.common import utils
from tempest.common import waiters
@@ -29,24 +31,11 @@
"""This is a basic minimum scenario test.
- This test below:
+ These tests below:
* across the multiple components
* as a regular user
* with and without optional parameters
* check command outputs
-
- Steps:
- 1. Create image
- 2. Create keypair
- 3. Boot instance with keypair and get list of instances
- 4. Create volume and show list of volumes
- 5. Attach volume to instance and getlist of volumes
- 6. Add IP to instance
- 7. Create and add security group to instance
- 8. Check SSH connection to instance
- 9. Reboot instance
- 10. Check SSH connection to instance after reboot
-
"""
def nova_show(self, server):
@@ -67,8 +56,9 @@
volume, custom_matchers.MatchesDictExceptForKeys(
got_volume, excluded_keys=excluded_keys))
- def nova_reboot(self, server):
- self.servers_client.reboot_server(server['id'], type='SOFT')
+ def nova_reboot(self, server, hard=False):
+ self.servers_client.reboot_server(server['id'],
+ type="HARD" if hard else "SOFT")
waiters.wait_for_server_status(self.servers_client,
server['id'], 'ACTIVE')
@@ -96,9 +86,37 @@
'%s' % (secgroup['id'], server['id']))
raise exceptions.TimeoutException(msg)
+ def _get_floating_ip_in_server_addresses(self, floating_ip, server):
+ for addresses in server['addresses'].values():
+ for address in addresses:
+ if (address['OS-EXT-IPS:type'] == 'floating' and
+ address['addr'] == floating_ip['floating_ip_address']):
+ return address
+
+ def _is_floating_ip_detached_from_server(self, server, floating_ip):
+ server_info = self.servers_client.show_server(
+ server['id'])['server']
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server_info)
+ return (not address)
+
@decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
@utils.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
+ """This is a basic minimum scenario with multiple components
+
+ Steps:
+ 1. Create image
+ 2. Create keypair
+ 3. Boot instance with keypair and get list of instances
+ 4. Create volume and show list of volumes
+ 5. Attach volume to instance and getlist of volumes
+ 6. Add IP to instance
+ 7. Create and add security group to instance
+ 8. Check SSH connection to instance
+ 9. Reboot instance
+ 10. Check SSH connection to instance after reboot
+ """
image = self.image_create()
keypair = self.create_keypair()
@@ -121,7 +139,7 @@
floating_ip = None
server = self.servers_client.show_server(server['id'])['server']
if (CONF.network_feature_enabled.floating_ips and
- CONF.network.floating_network_name):
+ CONF.network.floating_network_name):
fip = self.create_floating_ip(server)
floating_ip = self.associate_floating_ip(
fip, server)
@@ -154,3 +172,116 @@
waiters.wait_for_server_floating_ip(
self.servers_client, server, floating_ip,
wait_for_disassociate=True)
+
+ if not test_utils.call_until_true(
+ self._is_floating_ip_detached_from_server,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval, server, floating_ip):
+ msg = ("Floating IP '%s' should not be in server addresses: %s"
+ % (floating_ip['floating_ip_address'],
+ server['addresses']))
+ raise exceptions.TimeoutException(msg)
+
+ @decorators.idempotent_id('a8fd48ec-1d01-4895-b932-02321661ec1e')
+ @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
+ "Cinder volume snapshots are disabled")
+ @utils.services('compute', 'volume', 'image', 'network')
+ def test_minimum_basic_instance_hard_reboot_after_vol_snap_deletion(self):
+ """Test compute hard reboot after volume snapshot deleted
+
+ Steps:
+ 1. Create image
+ 2. Create keypair
+ 3. Boot instance with keypair and get list of instances
+ 4. Create volume and show list of volumes
+ 5. Attach volume to instance and getlist of volumes
+ 6. Create a snapshot from volume
+ 7. Add IP to instance
+ 8. Create and add security group to instance
+ 9. Check SSH connection to instance
+ 10. Write data timestamp to the attached volume
+ 11. Delete volume snapshot before reboot instance
+ 12. Reboot instance (HARD)
+ 13. Check SSH connection to instance after reboot
+ 14. Verify attached disk data timestamp post instance reboot
+ """
+ image = self.image_create()
+ keypair = self.create_keypair()
+
+ server = self.create_server(image_id=image, key_name=keypair['name'])
+ servers = self.servers_client.list_servers()['servers']
+ self.assertIn(server['id'], [x['id'] for x in servers])
+
+ self.nova_show(server)
+
+ volume = self.create_volume()
+ volumes = self.volumes_client.list_volumes()['volumes']
+ self.assertIn(volume['id'], [x['id'] for x in volumes])
+
+ self.cinder_show(volume)
+
+ volume = self.nova_volume_attach(server, volume)
+ self.addCleanup(self.nova_volume_detach, server, volume)
+ snapshot = self.create_volume_snapshot(volume['id'], force=True)
+ self.cinder_show(volume)
+
+ floating_ip = None
+ server = self.servers_client.show_server(server['id'])['server']
+ if (CONF.network_feature_enabled.floating_ips and
+ CONF.network.floating_network_name):
+ fip = self.create_floating_ip(server)
+ floating_ip = self.associate_floating_ip(
+ fip, server)
+ # fetch the server again to make sure the addresses were refreshed
+ # after associating the floating IP
+ server = self.servers_client.show_server(server['id'])['server']
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server)
+ self.assertIsNotNone(
+ address,
+ "Failed to find floating IP '%s' in server addresses: %s" %
+ (floating_ip['floating_ip_address'], server['addresses']))
+ ssh_ip = floating_ip['floating_ip_address']
+ else:
+ ssh_ip = self.get_server_ip(server)
+
+ self.create_and_add_security_group_to_server(server)
+
+ # check that we can SSH to the server before reboot
+ self.linux_client = self.get_remote_client(
+ ssh_ip, private_key=keypair['private_key'],
+ server=server)
+
+ # write data to the volume before reboot instance
+ timestamp_before = self.create_timestamp(
+ ssh_ip, private_key=keypair['private_key'], server=server)
+ # delete the snapshot before rebooting the instance
+ self.snapshots_client.delete_snapshot(snapshot['id'])
+ self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
+ self.nova_reboot(server, hard=True)
+
+ # check that we can SSH to the server after reboot
+ # (both connections are part of the scenario)
+ self.linux_client = self.get_remote_client(
+ ssh_ip, private_key=keypair['private_key'],
+ server=server)
+
+ self.check_disks()
+ timestamp_after = self.get_timestamp(
+ ssh_ip, private_key=keypair['private_key'], server=server)
+ self.assertEqual(timestamp_before, timestamp_after)
+ if floating_ip:
+ # delete the floating IP, this should refresh the server addresses
+ self.disassociate_floating_ip(floating_ip)
+ waiters.wait_for_server_floating_ip(
+ self.servers_client, server, floating_ip,
+ wait_for_disassociate=True)
+
+ if not test_utils.call_until_true(
+ self._is_floating_ip_detached_from_server,
+ CONF.compute.build_timeout, CONF.compute.build_interval,
+ server, floating_ip):
+ msg = ("Floating IP '%s' should not be in server addresses: %s"
+ % (floating_ip['floating_ip_address'],
+ server['addresses']))
+ raise exceptions.TimeoutException(msg)
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 0b34ae0..1f93903 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -98,7 +98,6 @@
- tempest-slow-py3:
irrelevant-files: *tempest-irrelevant-files
- nova-live-migration:
- voting: false
irrelevant-files: *tempest-irrelevant-files
- devstack-plugin-ceph-tempest-py3:
# TODO(kopecmartin): make it voting once the below bug is fixed
@@ -147,6 +146,8 @@
# irrelevant-files: *tempest-irrelevant-files
#- tempest-full-centos-9-stream:
# irrelevant-files: *tempest-irrelevant-files
+ - nova-live-migration:
+ irrelevant-files: *tempest-irrelevant-files
experimental:
jobs:
- tempest-with-latest-microversion