Source code for tempest.scenario.test_snapshots_with_add_location

# Copyright 2026 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.

from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.scenario import manager

CONF = config.CONF


[docs] class TestImageHashVerification(manager.ScenarioTest): """Test location, hash and checksum for images created via Nova and Cinder when do_secure_hash is enabled. These scenario tests verify end-to-end integration when Nova creates an instance snapshot or Cinder uploads a volume to Glance: * The image has at least one valid location entry. * When do_secure_hash is True, checksum, os_hash_algo and os_hash_value are populated after the location_import task. These tests run only when do_secure_hash=True. The do_secure_hash=False add-location contract is not exercised here because Nova and Cinder may use the traditional upload path (file-based Nova snapshot, non-optimized Cinder volume upload) instead of POST /v2/images/{id}/locations. Upload computes checksum independently of do_secure_hash, so asserting that hash fields remain None is not reliable in scenario tests. False-path coverage is provided by Glance functional tests and Tempest API tests (LocationImportTest and MultistoreLocationImportTest.test_add_location_with_do_secure_hash_false). """ @classmethod def skip_checks(cls): super(TestImageHashVerification, cls).skip_checks() if not CONF.compute_feature_enabled.snapshot: raise cls.skipException("Snapshotting is not available.") if not CONF.image_feature_enabled.do_secure_hash: raise cls.skipException( '%s skipped: do_secure_hash=False is covered by Glance ' 'functional and Tempest API tests, not Nova/Cinder ' 'scenario tests (upload path may set checksum)' % cls.__name__) @classmethod def resource_setup(cls): super(TestImageHashVerification, cls).resource_setup() if not cls.os_primary.image_versions_client.has_version('2.17'): raise cls.skipException( '%s skipped as Glance does not support v2.17' % cls.__name__) def _verify_image_location_and_hash(self, image_id, image_description): """Verify location is added and hash values are populated. When Nova or Cinder use the new add location API, the image should have a location entry populated. With do_secure_hash enabled in glance, hash computation happens asynchronously and hash values should be populated after the task completes. """ # Wait for all image tasks to reach 'success' status. # When glance receives an image via the add location API, # it spawns a background task for hash computation. waiters.wait_for_image_tasks_status( self.image_client, image_id, 'success') # Re-fetch image after tasks are complete image = self.image_client.show_image(image_id) self.assertEqual('active', image['status'], '%s is not in active status' % image_description) # Verify location has been added via the new add location API. # The image should have at least one location entry after # Nova/Cinder added the location. if 'locations' in image: self.assertGreaterEqual( len(image['locations']), 1, 'Expected at least one location for %s' % image_description) for loc in image['locations']: self.assertIn('url', loc, 'Location entry missing url for ' '%s' % image_description) self.assertTrue( len(loc['url']) > 0, 'Location url should not be empty for ' '%s' % image_description) # Verify size is populated (location must have been valid) self.assertIsNotNone( image['size'], 'Image size should not be None for %s' % image_description) # do_secure_hash=True is required; class is skipped otherwise. self.assertIsNotNone( image['checksum'], 'checksum should not be None for %s when ' 'do_secure_hash is enabled' % image_description) self.assertIsNotNone( image['os_hash_algo'], 'os_hash_algo should not be None for %s when ' 'do_secure_hash is enabled' % image_description) self.assertIsNotNone( image['os_hash_value'], 'os_hash_value should not be None for %s when ' 'do_secure_hash is enabled' % image_description) return image
[docs] @decorators.idempotent_id('a1b2c3d4-e5f6-7890-abcd-ef1234567890') @utils.services('compute', 'image') def test_instance_snapshot_image_hash_verification(self): """Test location and hash for instance snapshot image. This test verifies that when Nova creates a snapshot of an instance using the new add location API, the resulting image in Glance has: - A valid location entry added via the new add location API - Proper checksum, os_hash_algo and os_hash_value when do_secure_hash is enabled Steps: 1. Create an instance from the configured image 2. Create a snapshot of the instance 3. Wait for the background image task to complete 4. Verify the snapshot image has a valid location 5. Verify hash values are populated """ server = self.create_server(wait_until='ACTIVE') snapshot_name = data_utils.rand_name( prefix=CONF.resource_name_prefix, name='instance-snapshot-hash-test') snapshot_image = self.create_server_snapshot( server=server, name=snapshot_name) self._verify_image_location_and_hash( snapshot_image['id'], 'instance snapshot image')
[docs] @decorators.idempotent_id('b2c3d4e5-f6a7-8901-bcde-f12345678901') @utils.services('compute', 'volume', 'image') def test_volume_upload_image_hash_verification(self): """Test location and hash for volume uploaded to image. This test verifies that when Cinder uploads a volume as an image to Glance using the new add location API, the resulting image has: - A valid location entry added via the new add location API - Proper checksum, os_hash_algo and os_hash_value when do_secure_hash is enabled Steps: 1. Create a volume 2. Upload the volume to Glance as an image 3. Wait for the background image task to complete 4. Verify the resulting image has a valid location 5. Verify hash values are populated """ if not CONF.service_available.cinder: raise self.skipException("Cinder is not available") volume = self.create_volume() image_name = data_utils.rand_name( prefix=CONF.resource_name_prefix, name='volume-upload-hash-test') body = self.volumes_client.upload_volume( volume['id'], image_name=image_name, disk_format=CONF.volume.disk_format[0] )['os-volume_upload_image'] image_id = body['image_id'] self.addCleanup(test_utils.call_and_ignore_notfound_exc, self.image_client.delete_image, image_id) # Wait for the image to become active waiters.wait_for_image_status( self.image_client, image_id, 'active') # Wait for the volume to become available again waiters.wait_for_volume_resource_status( self.volumes_client, volume['id'], 'available') image = self._verify_image_location_and_hash( image_id, 'volume uploaded image') self.assertEqual(image_name, image['name'])