Merge pull request #509 from ionutbalutoiu/refactor-manila-ganesha-test
Refactor Manila Ganesha test
This commit is contained in:
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user