Source code for scenario.test_instances_with_cinder_volumes

# Copyright 2024 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 oslo_log import log as logging

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


CONF = config.CONF
LOG = logging.getLogger(__name__)


[docs] class TestInstancesWithCinderVolumes(manager.ScenarioTest): """This is cinder volumes test. Tests are below: * test_instances_with_cinder_volumes_on_all_compute_nodes """ compute_min_microversion = '2.60'
[docs] @decorators.idempotent_id('d0e3c1a3-4b0a-4b0e-8b0a-4b0e8b0a4b0e') @decorators.attr(type=['slow', 'multinode']) @utils.services('compute', 'volume', 'image', 'network') def test_instances_with_cinder_volumes_on_all_compute_nodes(self): """Test instances with cinder volumes launches on all compute nodes Steps: 1. Create an image 2. Create a keypair 3. Create a bootable volume from the image and of the given volume type 4. Boot an instance from the bootable volume on each available compute node, up to CONF.compute.min_compute_nodes 5. Create a volume using each volume_types_for_data_volume on all available compute nodes, up to CONF.compute.min_compute_nodes. Total number of volumes is equal to compute nodes * len(volume_types_for_data_volume) 6. Attach volumes to the instances 7. Assign floating IP to all instances 8. Configure security group for ssh access to all instances 9. Confirm ssh access to all instances 10. Run write test to all volumes through ssh connection per instance 11. Clean up the sources, an instance, volumes, keypair and image """ boot_volume_type = (CONF.volume.volume_type or self.create_volume_type()['name']) # create an image image = self.image_create() # create keypair keypair = self.create_keypair() # check all available zones for booting instances available_zone = \ self.os_admin.availability_zone_client.list_availability_zones( detail=True)['availabilityZoneInfo'] hosts = [] for zone in available_zone: if zone['zoneState']['available']: for host in zone['hosts']: if 'nova-compute' in zone['hosts'][host] and \ zone['hosts'][host]['nova-compute']['available'] and \ not host.endswith('-ironic'): hosts.append({'zone': zone['zoneName'], 'host_name': host}) # fail if there is less hosts than minimal number of instances if len(hosts) < CONF.compute.min_compute_nodes: raise exceptions.InvalidConfiguration( "Host list %s is shorter than min_compute_nodes. " % hosts) # get volume types volume_types = [] if CONF.volume_feature_enabled.volume_types_for_data_volume: types = CONF.volume_feature_enabled.volume_types_for_data_volume volume_types = types.split(',') else: # no user specified volume types, create 2 default ones volume_types.append(self.create_volume_type()['name']) volume_types.append(self.create_volume_type()['name']) hosts_to_boot_servers = hosts[:CONF.compute.min_compute_nodes] LOG.debug("List of hosts selected to boot servers %s: ", hosts_to_boot_servers) # create volumes so that we dont need to wait for them to be created # and save them in a list created_volumes = [] for host in hosts_to_boot_servers: for volume_type in volume_types: created_volumes.append( self.create_volume(volume_type=volume_type, wait_until=None) ) bootable_volumes = [] for host in hosts_to_boot_servers: # create boot volume from image and of the given volume type bootable_volumes.append( self.create_volume( imageRef=image, volume_type=boot_volume_type, wait_until=None) ) # boot server servers = [] for bootable_volume in bootable_volumes: # wait for bootable volumes to become available waiters.wait_for_volume_resource_status( self.volumes_client, bootable_volume['id'], 'available') # create an instance from bootable volume server = self.boot_instance_from_resource( source_id=bootable_volume['id'], source_type='volume', keypair=keypair, wait_until=None ) servers.append(server) start = 0 end = len(volume_types) for server in servers: attached_volumes = [] # wait for server to become active waiters.wait_for_server_status(self.servers_client, server['id'], 'ACTIVE') # attach volumes to the instances for volume in created_volumes[start:end]: # wait for volume to become available waiters.wait_for_volume_resource_status( self.volumes_client, volume['id'], 'available') attached_volume = self.nova_volume_attach(server, volume) attached_volumes.append(attached_volume) LOG.debug("Attached volume %s to server %s", attached_volume['id'], server['id']) # assign floating ip floating_ip = None 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) ssh_ip = floating_ip['floating_ip_address'] else: ssh_ip = self.get_server_ip(server) # create security group self.create_and_add_security_group_to_server(server) # confirm ssh access self.linux_client = self.get_remote_client( ssh_ip, private_key=keypair['private_key'], server=server ) # run write test on all volumes for volume in attached_volumes: waiters.wait_for_volume_resource_status( self.volumes_client, volume['id'], 'in-use') # get the mount path mount_path = f"/mnt/{volume['attachments'][0]['device'][5:]}" # create file for mounting on server self.create_file(ssh_ip, mount_path, private_key=keypair['private_key'], server=server) # dev name volume['attachments'][0]['device'][5:] is like # /dev/vdb, we need to remove /dev/ -> first 5 chars timestamp_before = self.create_timestamp( ssh_ip, private_key=keypair['private_key'], server=server, dev_name=volume['attachments'][0]['device'][5:], mount_path=mount_path ) timestamp_after = self.get_timestamp( ssh_ip, private_key=keypair['private_key'], server=server, dev_name=volume['attachments'][0]['device'][5:], mount_path=mount_path ) self.assertEqual(timestamp_before, timestamp_after) # delete volume self.nova_volume_detach(server, volume) self.volumes_client.delete_volume(volume['id']) 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) start += len(volume_types) end += len(volume_types)