Merge pull request #509 from ionutbalutoiu/refactor-manila-ganesha-test

Refactor Manila Ganesha test
This commit is contained in:
Aurelien Lourot
2021-03-15 13:21:55 +01:00
committed by GitHub
3 changed files with 276 additions and 111 deletions
+264
View File
@@ -16,12 +16,47 @@
"""Encapsulate Manila testing."""
import logging
import tenacity
from manilaclient import client as manilaclient
import zaza.model
import zaza.openstack.configure.guest as guest
import zaza.openstack.utilities.openstack as openstack_utils
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.charm_tests.nova.utils as nova_utils
import zaza.openstack.charm_tests.neutron.tests as neutron_tests
def verify_status(stdin, stdout, stderr):
"""Callable to verify the command output.
It checks if the command successfully executed.
This is meant to be given as parameter 'verify' to the helper function
'openstack_utils.ssh_command'.
"""
status = stdout.channel.recv_exit_status()
if status:
logging.info("{}".format(stderr.readlines()[0].strip()))
assert status == 0
def verify_manila_testing_file(stdin, stdout, stderr):
"""Callable to verify the command output.
It checks if the command successfully executed, and it validates the
testing file written on the Manila share.
This is meant to be given as parameter 'verify' to the helper function
'openstack_utils.ssh_command'.
"""
verify_status(stdin, stdout, stderr)
out = ""
for line in iter(stdout.readline, ""):
out += line
assert out == "test\n"
class ManilaTests(test_utils.OpenStackBaseTest):
@@ -49,3 +84,232 @@ class ManilaTests(test_utils.OpenStackBaseTest):
wait=tenacity.wait_exponential(multiplier=3, min=2, max=10))
def _list_shares(self):
return self.manila_client.shares.list()
class ManilaBaseTest(test_utils.OpenStackBaseTest):
"""Encapsulate a Manila basic functionality test."""
RESOURCE_PREFIX = 'zaza-manilatests'
INSTANCE_KEY = 'bionic'
INSTANCE_USERDATA = """#cloud-config
packages:
- nfs-common
"""
@classmethod
def setUpClass(cls):
"""Run class setup for running tests."""
super(ManilaBaseTest, cls).setUpClass()
cls.nova_client = openstack_utils.get_nova_session_client(
session=cls.keystone_session)
cls.manila_client = manilaclient.Client(
session=cls.keystone_session, client_version='2')
cls.share_name = 'test-manila-share'
cls.share_type_name = 'default_share_type'
cls.share_protocol = 'nfs'
cls.mount_dir = '/mnt/manila_share'
cls.share_network = None
@classmethod
def tearDownClass(cls):
"""Run class teardown after tests finished."""
# Cleanup Nova servers
logging.info('Cleaning up test Nova servers')
fips_reservations = []
for vm in cls.nova_client.servers.list():
fips_reservations += neutron_tests.floating_ips_from_instance(vm)
vm.delete()
openstack_utils.resource_removed(
cls.nova_client.servers,
vm.id,
msg="Waiting for the Nova VM {} to be deleted".format(vm.name))
# Delete FiPs reservations
logging.info('Cleaning up test FiPs reservations')
neutron = openstack_utils.get_neutron_session_client(
session=cls.keystone_session)
for fip in neutron.list_floatingips()['floatingips']:
if fip['floating_ip_address'] in fips_reservations:
neutron.delete_floatingip(fip['id'])
# Cleanup Manila shares
logging.info('Cleaning up test shares')
for share in cls.manila_client.shares.list():
share.delete()
openstack_utils.resource_removed(
cls.manila_client.shares,
share.id,
msg="Waiting for the Manila share {} to be deleted".format(
share.name))
# Cleanup test Manila share servers (spawned by the driver when DHSS
# is enabled).
logging.info('Cleaning up test shares servers (if found)')
for server in cls.manila_client.share_servers.list():
server.delete()
openstack_utils.resource_removed(
cls.manila_client.share_servers,
server.id,
msg="Waiting for the share server {} to be deleted".format(
server.id))
def _get_mount_options(self):
"""Get the appropriate mount options used to mount the Manila share.
:returns: The proper mount options flags for the share protocol.
:rtype: string
"""
if self.share_protocol == 'nfs':
return 'nfsvers=4.1,proto=tcp'
else:
raise NotImplementedError(
'Share protocol not supported yet: {}'.format(
self.share_protocol))
def _mount_share_on_instance(self, instance_ip, ssh_user_name,
ssh_private_key, share_path):
"""Mount a share into a Nova instance.
The mount command is executed via SSH.
:param instance_ip: IP of the Nova instance.
:type instance_ip: string
:param ssh_user_name: SSH user name.
:type ssh_user_name: string
:param ssh_private_key: SSH private key.
:type ssh_private_key: string
:param share_path: Share network path.
:type share_path: string
"""
ssh_cmd = (
'sudo mkdir -p {0} && '
'sudo mount -t {1} -o {2} {3} {0}'.format(
self.mount_dir,
self.share_protocol,
self._get_mount_options(),
share_path))
for attempt in tenacity.Retrying(
stop=tenacity.stop_after_attempt(5),
wait=tenacity.wait_exponential(multiplier=3, min=2, max=10)):
with attempt:
openstack_utils.ssh_command(
vm_name="instance-{}".format(instance_ip),
ip=instance_ip,
username=ssh_user_name,
privkey=ssh_private_key,
command=ssh_cmd,
verify=verify_status)
@tenacity.retry(
stop=tenacity.stop_after_attempt(5),
wait=tenacity.wait_exponential(multiplier=3, min=2, max=10))
def _write_testing_file_on_instance(self, instance_ip, ssh_user_name,
ssh_private_key):
"""Write a file on a Manila share mounted into a Nova instance.
Write a testing file into the already mounted Manila share from the
given Nova instance (which is meant to be validated from another
instance). These commands are executed via SSH.
:param instance_ip: IP of the Nova instance.
:type instance_ip: string
:param ssh_user_name: SSH user name.
:type ssh_user_name: string
:param ssh_private_key: SSH private key.
:type ssh_private_key: string
"""
openstack_utils.ssh_command(
vm_name="instance-{}".format(instance_ip),
ip=instance_ip,
username=ssh_user_name,
privkey=ssh_private_key,
command='echo "test" | sudo tee {}/test'.format(
self.mount_dir),
verify=verify_status)
@tenacity.retry(
stop=tenacity.stop_after_attempt(5),
wait=tenacity.wait_exponential(multiplier=3, min=2, max=10))
def _validate_testing_file_from_instance(self, instance_ip, ssh_user_name,
ssh_private_key):
"""Validate a file from the Manila share mounted into a Nova instance.
This is meant to run after the testing file was already written into
another Nova instance. It validates the written file. The commands are
executed via SSH.
:param instance_ip: IP of the Nova instance.
:type instance_ip: string
:param ssh_user_name: SSH user name.
:type ssh_user_name: string
:param ssh_private_key: SSH private key.
:type ssh_private_key: string
"""
openstack_utils.ssh_command(
vm_name="instance-{}".format(instance_ip),
ip=instance_ip,
username=ssh_user_name,
privkey=ssh_private_key,
command='sudo cat {}/test'.format(self.mount_dir),
verify=verify_manila_testing_file)
def test_manila_share(self):
"""Test that a Manila share can be accessed on two instances.
1. Create a share
2. Spawn two servers
3. Mount it on both
4. Write a file on one
5. Read it on the other
6. Profit
"""
# Create a share
share = self.manila_client.shares.create(
share_type=self.share_type_name,
name=self.share_name,
share_proto=self.share_protocol,
share_network=self.share_network,
size=1)
# Spawn Servers
instance_1 = self.launch_guest(
guest_name='ins-1',
userdata=self.INSTANCE_USERDATA,
instance_key=self.INSTANCE_KEY)
instance_2 = self.launch_guest(
guest_name='ins-2',
userdata=self.INSTANCE_USERDATA,
instance_key=self.INSTANCE_KEY)
fip_1 = neutron_tests.floating_ips_from_instance(instance_1)[0]
fip_2 = neutron_tests.floating_ips_from_instance(instance_2)[0]
# Wait for the created share to become available before it gets used.
openstack_utils.resource_reaches_status(
self.manila_client.shares,
share.id,
wait_iteration_max_time=120,
stop_after_attempt=2,
expected_status="available",
msg="Waiting for a share to become available")
# Grant access to the Manila share for both Nova instances.
share.allow(access_type='ip', access=fip_1, access_level='rw')
share.allow(access_type='ip', access=fip_2, access_level='rw')
ssh_user_name = guest.boot_tests[self.INSTANCE_KEY]['username']
privkey = openstack_utils.get_private_key(nova_utils.KEYPAIR_NAME)
share_path = share.export_locations[0]
# Write a testing file on instance #1
self._mount_share_on_instance(
fip_1, ssh_user_name, privkey, share_path)
self._write_testing_file_on_instance(
fip_1, ssh_user_name, privkey)
# Validate the testing file from instance #2
self._mount_share_on_instance(
fip_2, ssh_user_name, privkey, share_path)
self._validate_testing_file_from_instance(
fip_2, ssh_user_name, privkey)
@@ -23,6 +23,9 @@ import zaza.openstack.utilities.openstack as openstack_utils
from manilaclient import client as manilaclient
MANILA_GANESHA_TYPE_NAME = "cephfsnfstype"
def setup_ganesha_share_type(manila_client=None):
"""Create a share type for manila with Ganesha.
@@ -35,7 +38,7 @@ def setup_ganesha_share_type(manila_client=None):
session=keystone_session, client_version='2')
manila_client.share_types.create(
name="cephfsnfstype", spec_driver_handles_share_servers=False,
name=MANILA_GANESHA_TYPE_NAME, spec_driver_handles_share_servers=False,
extra_specs={
'vendor_name': 'Ceph',
'storage_protocol': 'NFS',
@@ -16,122 +16,20 @@
"""Encapsulate Manila Ganesha testing."""
import logging
from zaza.openstack.charm_tests.manila_ganesha.setup import (
MANILA_GANESHA_TYPE_NAME,
)
from tenacity import Retrying, stop_after_attempt, wait_exponential
from manilaclient import client as manilaclient
import zaza.openstack.charm_tests.neutron.tests as neutron_tests
import zaza.openstack.charm_tests.nova.utils as nova_utils
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.configure.guest as guest
import zaza.openstack.utilities.openstack as openstack_utils
import zaza.openstack.charm_tests.manila.tests as manila_tests
class ManilaGaneshaTests(test_utils.OpenStackBaseTest):
class ManilaGaneshaTests(manila_tests.ManilaBaseTest):
"""Encapsulate Manila Ganesha tests."""
RESOURCE_PREFIX = 'zaza-manilatests'
INSTANCE_USERDATA = """#cloud-config
packages:
- nfs-common
"""
@classmethod
def setUpClass(cls):
"""Run class setup for running tests."""
super(ManilaGaneshaTests, cls).setUpClass()
cls.nova_client = (
openstack_utils.get_nova_session_client(cls.keystone_session))
cls.manila_client = manilaclient.Client(
session=cls.keystone_session, client_version='2')
def test_manila_share(self):
"""Test that Manila + Ganesha shares can be accessed on two instances.
1. create a share
2. Spawn two servers
3. mount it on both
4. write a file on one
5. read it on the other
6. profit
"""
# Create a share
share = self.manila_client.shares.create(
share_type='cephfsnfstype', name='cephnfsshare1',
share_proto="nfs", size=1)
# Spawn Servers
instance_1, instance_2 = self.launch_guests(
userdata=self.INSTANCE_USERDATA)
fip_1 = neutron_tests.floating_ips_from_instance(instance_1)[0]
fip_2 = neutron_tests.floating_ips_from_instance(instance_2)[0]
# Wait for the created share to become available before it gets used.
openstack_utils.resource_reaches_status(
self.manila_client.shares,
share.id,
wait_iteration_max_time=120,
stop_after_attempt=2,
expected_status="available",
msg="Waiting for a share to become available")
share.allow(access_type='ip', access=fip_1, access_level='rw')
share.allow(access_type='ip', access=fip_2, access_level='rw')
# Mount Share
username = guest.boot_tests['bionic']['username']
password = guest.boot_tests['bionic'].get('password')
privkey = openstack_utils.get_private_key(nova_utils.KEYPAIR_NAME)
# Write a file on instance_1
def verify_setup(stdin, stdout, stderr):
status = stdout.channel.recv_exit_status()
if status:
logging.info("{}".format(stderr.readlines()[0].strip()))
self.assertEqual(status, 0)
mount_path = share.export_locations[0]
for attempt in Retrying(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)):
with attempt:
openstack_utils.ssh_command(
username, fip_1, 'instance-1',
'sudo mkdir -p /mnt/ceph && '
'sudo mount -t nfs -o nfsvers=4.1,proto=tcp '
'{} /mnt/ceph && '
'echo "test" | sudo tee /mnt/ceph/test'.format(
mount_path),
password=password, privkey=privkey, verify=verify_setup)
for attempt in Retrying(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)):
with attempt:
# Setup that file on instance_2
openstack_utils.ssh_command(
username, fip_2, 'instance-2',
'sudo mkdir -p /mnt/ceph && '
'sudo /bin/mount -t nfs -o nfsvers=4.1,proto=tcp '
'{} /mnt/ceph'
.format(mount_path),
password=password, privkey=privkey, verify=verify_setup)
def verify(stdin, stdout, stderr):
status = stdout.channel.recv_exit_status()
if status:
logging.info("{}".format(stderr.readlines()[0].strip()))
self.assertEqual(status, 0)
out = ""
for line in iter(stdout.readline, ""):
out += line
self.assertEqual(out, "test\n")
openstack_utils.ssh_command(
username, fip_2, 'instance-2',
'sudo cat /mnt/ceph/test',
password=password, privkey=privkey, verify=verify)
cls.share_name = 'cephnfsshare1'
cls.share_type_name = MANILA_GANESHA_TYPE_NAME
cls.share_protocol = 'nfs'