Move shared logic to base scenario test class

The ShareBasicOpsBase class contained setup logic which should be
reused in other tests. This code is moved up to ShareScenarioTest.
Additionally setup checks are moved up to avoid unnecessarily creating
resources, and some naming changes have been made for clarity.

Change-Id: Ia7db48ae0ecab7a11b1d724b6ca71015ee675aea
This commit is contained in:
Nir Gilboa 2018-01-20 22:54:57 +02:00
parent 4c99f09457
commit 5324a7c655
2 changed files with 397 additions and 379 deletions

View File

@ -16,13 +16,20 @@
from oslo_log import log
import six
from tempest import config
from tempest.lib.common.utils import data_utils
from manila_tempest_tests.common import constants
from manila_tempest_tests.common import remote_client
from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.scenario import manager
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 exceptions
from tempfile import mkstemp
from urllib2 import urlopen
CONF = config.CONF
LOG = log.getLogger(__name__)
@ -31,6 +38,12 @@ class ShareScenarioTest(manager.NetworkScenarioTest):
"""Provide harness to do Manila scenario tests."""
credentials = ('admin', 'primary')
protocol = None
ip_version = 4
@property
def ipv6_enabled(self):
return self.ip_version == 6
@classmethod
def resource_setup(cls):
@ -48,6 +61,266 @@ class ShareScenarioTest(manager.NetworkScenarioTest):
if not CONF.service_available.manila:
raise cls.skipException("Manila support is required")
def setUp(self):
base.verify_test_has_appropriate_tags(self)
if self.ipv6_enabled and not CONF.share.run_ipv6_tests:
raise self.skipException("IPv6 tests are disabled")
if self.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled" % self.protocol
raise self.skipException(message)
if self.protocol not in CONF.share.enable_ip_rules_for_protocols:
message = ("%s tests for access rules other than IP are disabled" %
self.protocol)
raise self.skipException(message)
super(ShareScenarioTest, self).setUp()
self.image_id = None
# Setup image and flavor the test instance
# Support both configured and injected values
self.floating_ips = {}
if not hasattr(self, 'flavor_ref'):
self.flavor_ref = CONF.share.client_vm_flavor_ref
if CONF.share.image_with_share_tools == 'centos':
self.image_ref = self._create_centos_based_glance_image()
elif CONF.share.image_with_share_tools:
images = self.compute_images_client.list_images()["images"]
for img in images:
if img["name"] == CONF.share.image_with_share_tools:
self.image_id = img['id']
break
if not self.image_id:
msg = ("Image %s not found. Expecting an image including "
"required share tools." %
CONF.share.image_with_share_tools)
raise exceptions.InvalidConfiguration(message=msg)
self.ssh_user = CONF.share.image_username
LOG.debug('Starting test for i:{image_id}, f:{flavor}. '
'user: {ssh_user}'.format(image_id=self.image_id,
flavor=self.flavor_ref,
ssh_user=self.ssh_user))
self.security_group = self._create_security_group()
self.share_network = self.create_share_network()
def mount_share(self, location, remote_client, target_dir=None):
raise NotImplementedError
def umount_share(self, remote_client, target_dir=None):
target_dir = target_dir or "/mnt"
remote_client.exec_command("sudo umount %s" % target_dir)
def create_share_network(self):
self.net = self._create_network(namestart="manila-share")
self.subnet = self._create_subnet(
network=self.net,
namestart="manila-share-sub",
ip_version=self.ip_version,
use_default_subnetpool=self.ipv6_enabled)
router = self._get_router()
self._create_router_interface(subnet_id=self.subnet['id'],
router_id=router['id'])
share_network = self._create_share_network(
neutron_net_id=self.net['id'],
neutron_subnet_id=self.subnet['id'],
name=data_utils.rand_name("sn-name"))
return share_network
def boot_instance(self, wait_until="ACTIVE"):
self.keypair = self.create_keypair()
security_groups = [{'name': self.security_group['name']}]
create_kwargs = {
'key_name': self.keypair['name'],
'security_groups': security_groups,
'wait_until': wait_until,
'networks': [{'uuid': self.net['id']}, ],
}
instance = self.create_server(
image_id=self.image_id, flavor=self.flavor_ref, **create_kwargs)
return instance
def init_remote_client(self, instance):
if self.ipv6_enabled:
server_ip = self._get_ipv6_server_ip(instance)
else:
# Obtain a floating IP
floating_ip = (
self.compute_floating_ips_client.create_floating_ip()
['floating_ip'])
self.floating_ips[instance['id']] = floating_ip
self.addCleanup(
test_utils.call_and_ignore_notfound_exc,
self.compute_floating_ips_client.delete_floating_ip,
floating_ip['id'])
# Attach a floating IP
self.compute_floating_ips_client.associate_floating_ip_to_server(
floating_ip['ip'], instance['id'])
server_ip = floating_ip['ip']
self.assertIsNotNone(server_ip)
# Check ssh
remote_client = self.get_remote_client(
server_or_ip=server_ip,
username=self.ssh_user,
private_key=self.keypair['private_key'])
# NOTE(u_glide): Workaround for bug #1465682
remote_client = remote_client.ssh_client
self.share = self.shares_client.get_share(self.share['id'])
return remote_client
def write_data_to_mounted_share(self, escaped_string, remote_client,
mount_point='/mnt/t1'):
remote_client.exec_command("echo \"{escaped_string}\" "
"| sudo tee {mount_point} && sudo sync"
.format(escaped_string=escaped_string,
mount_point=mount_point))
def read_data_from_mounted_share(self,
remote_client,
mount_point='/mnt/t1'):
data = remote_client.exec_command("sudo cat {mount_point}"
.format(mount_point=mount_point))
return data.rstrip()
def migrate_share(self, share_id, dest_host, status,
force_host_assisted=False):
share = self._migrate_share(
share_id, dest_host, status, force_host_assisted,
self.shares_admin_v2_client)
return share
def migration_complete(self, share_id, dest_host):
return self._migration_complete(share_id, dest_host)
def create_share(self, **kwargs):
kwargs.update({
'share_protocol': self.protocol,
})
if not ('share_type_id' in kwargs or 'snapshot_id' in kwargs):
default_share_type_id = self._get_share_type()['id']
kwargs.update({'share_type_id': default_share_type_id})
if CONF.share.multitenancy_enabled:
kwargs.update({'share_network_id': self.share_net['id']})
self.share = self._create_share(**kwargs)
return self.share
def get_remote_client(self, *args, **kwargs):
if not CONF.share.image_with_share_tools:
return super(ShareScenarioTest,
self).get_remote_client(*args, **kwargs)
# NOTE(u_glide): We need custom implementation of this method until
# original implementation depends on CONF.compute.ssh_auth_method
# option.
server_or_ip = kwargs['server_or_ip']
if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
addr = server_or_ip['addresses'][
CONF.validation.network_for_ssh][0]
ip = addr['addr']
# NOTE(u_glide): Both options (pkey and password) are required here to
# support service images without Nova metadata support
client_params = {
'username': kwargs['username'],
'password': CONF.share.image_password,
'pkey': kwargs.get('private_key'),
}
linux_client = remote_client.RemoteClient(ip, **client_params)
try:
linux_client.validate_authentication()
except Exception:
LOG.exception('Initializing SSH connection to %s failed', ip)
self._log_console_output()
raise
return linux_client
def allow_access_ip(self, share_id, ip=None, instance=None,
access_level="rw", cleanup=True, snapshot=None):
if instance and not ip:
try:
net_addresses = instance['addresses']
first_address = net_addresses.values()[0][0]
ip = first_address['addr']
except Exception:
LOG.debug("Instance has no valid IP address: %s", instance)
# In case on an error ip will be still none
LOG.exception("Instance has no valid IP address. "
"Falling back to default")
if not ip:
ip = '0.0.0.0/0'
if snapshot:
self._allow_access_snapshot(snapshot['id'], access_type='ip',
access_to=ip, cleanup=cleanup)
else:
return self._allow_access(share_id, access_type='ip',
access_level=access_level, access_to=ip,
cleanup=cleanup,
client=self.shares_v2_client)
def deny_access(self, share_id, access_rule_id, client=None):
"""Deny share access
:param share_id: id of the share
:param access_rule_id: id of the rule that will be deleted
"""
client = client or self.shares_client
client.delete_access_rule(share_id, access_rule_id)
self.shares_v2_client.wait_for_share_status(
share_id, "active", status_attr='access_rules_status')
def provide_access_to_auxiliary_instance(self, instance, share=None,
snapshot=None, access_level='rw'):
share = share or self.share
if self.protocol.lower() == 'cifs':
self.allow_access_ip(
share['id'], instance=instance, cleanup=False,
snapshot=snapshot, access_level=access_level)
elif not CONF.share.multitenancy_enabled:
if self.ipv6_enabled:
server_ip = self._get_ipv6_server_ip(instance)
else:
server_ip = (CONF.share.override_ip_for_nfs_access or
self.floating_ips[instance['id']]['ip'])
self.assertIsNotNone(server_ip)
return self.allow_access_ip(
share['id'], ip=server_ip,
instance=instance, cleanup=False, snapshot=snapshot,
access_level=access_level)
elif (CONF.share.multitenancy_enabled and
self.protocol.lower() == 'nfs'):
return self.allow_access_ip(
share['id'], instance=instance, cleanup=False,
snapshot=snapshot, access_level=access_level)
def wait_for_active_instance(self, instance_id):
waiters.wait_for_server_status(
self.os_primary.servers_client, instance_id, "ACTIVE")
return self.os_primary.servers_client.show_server(
instance_id)["server"]
def _get_share_type(self):
if CONF.share.default_share_type_name:
return self.shares_client.get_share_type(
CONF.share.default_share_type_name)['share_type']
return self._create_share_type(
data_utils.rand_name("share_type"),
extra_specs={
'snapshot_support': CONF.share.capability_snapshot_support,
'driver_handles_share_servers': CONF.share.multitenancy_enabled
},)['share_type']
def _get_ipv6_server_ip(self, instance):
for net_list in instance['addresses'].values():
for net_data in net_list:
if net_data['version'] == 6:
return net_data['addr']
def _create_share(self, share_protocol=None, size=None, name=None,
snapshot_id=None, description=None, metadata=None,
share_network_id=None, share_type_id=None,
@ -160,17 +433,6 @@ class ShareScenarioTest(manager.NetworkScenarioTest):
self.addCleanup(client.delete_access_rule, share_id, access['id'])
return access
def _deny_access(self, share_id, rule_id, client=None):
"""Deny share access
:param share_id: id of the share
:param rule_id: id of the rule that will be deleted
"""
client = client or self.shares_client
client.delete_access_rule(share_id, rule_id)
self.shares_v2_client.wait_for_share_status(
share_id, "active", status_attr='access_rules_status')
def _allow_access_snapshot(self, snapshot_id, access_type="ip",
access_to="0.0.0.0/0", cleanup=True):
"""Allow snapshot access
@ -206,39 +468,6 @@ class ShareScenarioTest(manager.NetworkScenarioTest):
self.addCleanup(
client.remove_router_interface, router_id, subnet_id=subnet_id)
def get_remote_client(self, *args, **kwargs):
if not CONF.share.image_with_share_tools:
return super(ShareScenarioTest,
self).get_remote_client(*args, **kwargs)
# NOTE(u_glide): We need custom implementation of this method until
# original implementation depends on CONF.compute.ssh_auth_method
# option.
server_or_ip = kwargs['server_or_ip']
if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
addr = server_or_ip['addresses'][
CONF.validation.network_for_ssh][0]
ip = addr['addr']
# NOTE(u_glide): Both options (pkey and password) are required here to
# support service images without Nova metadata support
client_params = {
'username': kwargs['username'],
'password': CONF.share.image_password,
'pkey': kwargs.get('private_key'),
}
linux_client = remote_client.RemoteClient(ip, **client_params)
try:
linux_client.validate_authentication()
except Exception:
LOG.exception('Initializing SSH connection to %s failed', ip)
self._log_console_output()
raise
return linux_client
def _migrate_share(self, share_id, dest_host, status, force_host_assisted,
client=None):
client = client or self.shares_admin_v2_client
@ -264,3 +493,21 @@ class ShareScenarioTest(manager.NetworkScenarioTest):
self.addCleanup(self.shares_admin_v2_client.delete_share_type,
share_type['share_type']['id'])
return share_type
def _create_centos_based_glance_image(self):
imagepath = mkstemp(suffix='.qcow2')[1]
imagefile = open(imagepath, 'wb+')
image_response = urlopen('http://cloud.centos.org/centos/7/images/' +
'CentOS-7-x86_64-GenericCloud.qcow2')
LOG.info('Downloading CentOS7 image')
while True:
imagecopy = image_response.read(100 * 1024 * 1024)
if imagecopy == '':
break
imagefile.write(imagecopy)
imagefile.close()
LOG.info('Creating Glance image using the downloaded image file')
return self._image_create('centos', 'bare', imagepath, 'qcow2')

View File

@ -16,10 +16,7 @@
import ddt
from oslo_log import log as logging
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 exceptions
import testtools
from testtools import testcase as tc
@ -29,11 +26,7 @@ from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.scenario import manager_share as manager
from manila_tempest_tests import utils
from tempfile import mkstemp
from urllib2 import urlopen
CONF = config.CONF
LOG = logging.getLogger(__name__)
@ -50,225 +43,6 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
* Mount share
* Terminate the instance
"""
protocol = None
ip_version = 4
@property
def use_ipv6(self):
return self.ip_version == 6
def setUp(self):
super(ShareBasicOpsBase, self).setUp()
if self.use_ipv6 and not CONF.share.run_ipv6_tests:
raise self.skipException("IPv6 tests are disabled")
base.verify_test_has_appropriate_tags(self)
self.image_ref = None
# Setup image and flavor the test instance
# Support both configured and injected values
self.floatings = {}
if self.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled" % self.protocol
raise self.skipException(message)
if self.protocol not in CONF.share.enable_ip_rules_for_protocols:
message = ("%s tests for access rules other than IP are disabled" %
self.protocol)
raise self.skipException(message)
if not hasattr(self, 'flavor_ref'):
self.flavor_ref = CONF.share.client_vm_flavor_ref
if CONF.share.image_with_share_tools == 'centos':
self.image_ref = self._create_centos_based_glance_image()
elif CONF.share.image_with_share_tools:
images = self.compute_images_client.list_images()["images"]
for img in images:
if img["name"] == CONF.share.image_with_share_tools:
self.image_ref = img['id']
break
if not self.image_ref:
msg = ("Image %s not found" %
CONF.share.image_with_share_tools)
raise exceptions.InvalidConfiguration(message=msg)
self.ssh_user = CONF.share.image_username
LOG.debug('Starting test for i:{image}, f:{flavor}. '
'user: {ssh_user}'.format(
image=self.image_ref, flavor=self.flavor_ref,
ssh_user=self.ssh_user))
self.security_group = self._create_security_group()
self.create_share_network()
def boot_instance(self, wait_until="ACTIVE"):
self.keypair = self.create_keypair()
security_groups = [{'name': self.security_group['name']}]
create_kwargs = {
'key_name': self.keypair['name'],
'security_groups': security_groups,
'wait_until': wait_until,
'networks': [{'uuid': self.net['id']}, ],
}
instance = self.create_server(
image_id=self.image_ref, flavor=self.flavor_ref, **create_kwargs)
return instance
def init_ssh(self, instance):
if self.use_ipv6:
server_ip = self._get_ipv6_server_ip(instance)
else:
# Obtain a floating IP
floating_ip = (
self.compute_floating_ips_client.create_floating_ip()
['floating_ip'])
self.floatings[instance['id']] = floating_ip
self.addCleanup(
test_utils.call_and_ignore_notfound_exc,
self.compute_floating_ips_client.delete_floating_ip,
floating_ip['id'])
# Attach a floating IP
self.compute_floating_ips_client.associate_floating_ip_to_server(
floating_ip['ip'], instance['id'])
server_ip = floating_ip['ip']
self.assertIsNotNone(server_ip)
# Check ssh
ssh_client = self.get_remote_client(
server_or_ip=server_ip,
username=self.ssh_user,
private_key=self.keypair['private_key'])
# NOTE(u_glide): Workaround for bug #1465682
ssh_client = ssh_client.ssh_client
self.share = self.shares_client.get_share(self.share['id'])
return ssh_client
def mount_share(self, location, ssh_client, target_dir=None):
raise NotImplementedError
def umount_share(self, ssh_client, target_dir=None):
target_dir = target_dir or "/mnt"
ssh_client.exec_command("sudo umount %s" % target_dir)
def write_data(self, data, ssh_client):
ssh_client.exec_command("echo \"%s\" | sudo tee /mnt/t1 && sudo sync" %
data)
def read_data(self, ssh_client):
data = ssh_client.exec_command("sudo cat /mnt/t1")
return data.rstrip()
def migrate_share(self, share_id, dest_host, status, force_host_assisted):
share = self._migrate_share(
share_id, dest_host, status, force_host_assisted,
self.shares_admin_v2_client)
return share
def migration_complete(self, share_id, dest_host):
return self._migration_complete(share_id, dest_host)
def create_share_network(self):
self.net = self._create_network(namestart="manila-share")
self.subnet = self._create_subnet(
network=self.net,
namestart="manila-share-sub",
ip_version=self.ip_version,
use_default_subnetpool=self.use_ipv6)
router = self._get_router()
self._create_router_interface(subnet_id=self.subnet['id'],
router_id=router['id'])
self.share_net = self._create_share_network(
neutron_net_id=self.net['id'],
neutron_subnet_id=self.subnet['id'],
name=data_utils.rand_name("sn-name"))
def _get_ipv6_server_ip(self, instance):
for net_list in instance['addresses'].values():
for net_data in net_list:
if net_data['version'] == 6:
return net_data['addr']
def _get_share_type(self):
if CONF.share.default_share_type_name:
return self.shares_client.get_share_type(
CONF.share.default_share_type_name)['share_type']
return self._create_share_type(
data_utils.rand_name("share_type"),
extra_specs={
'snapshot_support': CONF.share.capability_snapshot_support,
'driver_handles_share_servers': CONF.share.multitenancy_enabled
},)['share_type']
def create_share(self, **kwargs):
kwargs.update({
'share_protocol': self.protocol,
})
if not ('share_type_id' in kwargs or 'snapshot_id' in kwargs):
kwargs.update({'share_type_id': self._get_share_type()['id']})
if CONF.share.multitenancy_enabled:
kwargs.update({'share_network_id': self.share_net['id']})
self.share = self._create_share(**kwargs)
return self.share
def allow_access_ip(self, share_id, ip=None, instance=None,
access_level="rw", cleanup=True, snapshot=None):
if instance and not ip:
try:
net_addresses = instance['addresses']
first_address = net_addresses.values()[0][0]
ip = first_address['addr']
except Exception:
LOG.debug("Instance: %s", instance)
# In case on an error ip will be still none
LOG.exception("Instance does not have a valid IP address."
"Falling back to default")
if not ip:
ip = '0.0.0.0/0'
if snapshot:
self._allow_access_snapshot(snapshot['id'], access_type='ip',
access_to=ip, cleanup=cleanup)
else:
return self._allow_access(share_id, access_type='ip',
access_level=access_level, access_to=ip,
cleanup=cleanup,
client=self.shares_v2_client)
def deny_access(self, share_id, access_rule_id):
self._deny_access(share_id, access_rule_id)
def provide_access_to_auxiliary_instance(self, instance, share=None,
snapshot=None, access_level='rw'):
share = share or self.share
if self.protocol.lower() == 'cifs':
return self.allow_access_ip(
share['id'], instance=instance, cleanup=False,
snapshot=snapshot, access_level=access_level)
elif not CONF.share.multitenancy_enabled:
if self.use_ipv6:
server_ip = self._get_ipv6_server_ip(instance)
else:
server_ip = (CONF.share.override_ip_for_nfs_access or
self.floatings[instance['id']]['ip'])
self.assertIsNotNone(server_ip)
return self.allow_access_ip(
share['id'], ip=server_ip,
instance=instance, cleanup=False, snapshot=snapshot,
access_level=access_level)
elif (CONF.share.multitenancy_enabled and
self.protocol.lower() == 'nfs'):
return self.allow_access_ip(
share['id'], instance=instance, cleanup=False,
snapshot=snapshot, access_level=access_level)
def wait_for_active_instance(self, instance_id):
waiters.wait_for_server_status(
self.os_primary.servers_client, instance_id, "ACTIVE")
return self.os_primary.servers_client.show_server(
instance_id)["server"]
def _ping_export_location(self, export, ssh_client):
ip, version = self.get_ip_and_version_from_export_location(export)
if version == 6:
ssh_client.exec_command("ping6 -c 1 %s" % ip)
else:
ssh_client.exec_command("ping -c 1 %s" % ip)
def get_ip_and_version_from_export_location(self, export):
export = export.replace('[', '').replace(']', '')
@ -284,6 +58,13 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
raise self.skipException(message)
return ip, version
def _ping_host_from_export_location(self, export, remote_client):
ip, version = self.get_ip_and_version_from_export_location(export)
if version == 6:
remote_client.exec_command("ping6 -c 1 %s" % ip)
else:
remote_client.exec_command("ping -c 1 %s" % ip)
def _get_export_locations_according_to_ip_version(
self, all_locations, error_on_invalid_ip_version):
locations = [
@ -297,6 +78,21 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
raise self.skipException(message)
return locations
def _get_user_export_locations(self, share=None, snapshot=None,
error_on_invalid_ip_version=False):
locations = None
if share:
locations = self._get_share_export_locations(share)
elif snapshot:
locations = self._get_snapshot_export_locations(snapshot)
self.assertNotEmpty(locations)
locations = self._get_export_locations_according_to_ip_version(
locations, error_on_invalid_ip_version)
self.assertNotEmpty(locations)
return locations
def _get_share_export_locations(self, share):
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
@ -308,23 +104,12 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
return locations
def _create_centos_based_glance_image(self):
imagepath = mkstemp(suffix='.qcow2')[1]
imagefile = open(imagepath, 'wb+')
image_response = urlopen('http://cloud.centos.org/centos/7/images/' +
'CentOS-7-x86_64-GenericCloud.qcow2')
def _get_snapshot_export_locations(self, snapshot):
exports = (self.shares_v2_client.
list_snapshot_export_locations(snapshot['id']))
locations = [x['path'] for x in exports]
LOG.info('Downloading CentOS7 image')
while True:
imagecopy = image_response.read(100 * 1024 * 1024)
if imagecopy == '':
break
imagefile.write(imagecopy)
imagefile.close()
LOG.info('Creating Glance image using the downloaded image file')
return self._image_create('centos', 'bare', imagepath, 'qcow2')
return locations
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_mount_share_one_vm(self):
@ -332,19 +117,12 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
self.create_share()
locations = self._get_user_export_locations(self.share)
instance = self.wait_for_active_instance(instance["id"])
ssh_client = self.init_ssh(instance)
remote_client = self.init_remote_client(instance)
self.provide_access_to_auxiliary_instance(instance)
for location in locations:
self.mount_share(location, ssh_client)
self.umount_share(ssh_client)
def _get_snapshot_export_locations(self, snapshot):
exports = (self.shares_v2_client.
list_snapshot_export_locations(snapshot['id']))
locations = [x['path'] for x in exports]
return locations
self.mount_share(location, remote_client)
self.umount_share(remote_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
def test_write_with_ro_access(self):
@ -356,20 +134,21 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
location = self._get_user_export_locations(self.share)[0]
instance = self.wait_for_active_instance(instance["id"])
ssh_client_inst = self.init_ssh(instance)
remote_client_inst = self.init_remote_client(instance)
# First, check if write works RW access.
acc_rule_id = self.provide_access_to_auxiliary_instance(instance)['id']
self.mount_share(location, ssh_client_inst)
self.write_data(test_data, ssh_client_inst)
self.mount_share(location, remote_client_inst)
self.write_data_to_mounted_share(test_data, remote_client_inst)
self.deny_access(self.share['id'], acc_rule_id)
self.provide_access_to_auxiliary_instance(instance, access_level='ro')
self.addCleanup(self.umount_share, ssh_client_inst)
self.addCleanup(self.umount_share, remote_client_inst)
# Test if write with RO access fails.
self.assertRaises(exceptions.SSHExecCommandFailed,
self.write_data, test_data, ssh_client_inst)
self.write_data_to_mounted_share,
test_data, remote_client_inst)
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_read_write_two_vms(self):
@ -385,23 +164,23 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
instance2 = self.wait_for_active_instance(instance2["id"])
# Write data to first VM
ssh_client_inst1 = self.init_ssh(instance1)
remote_client_inst1 = self.init_remote_client(instance1)
self.provide_access_to_auxiliary_instance(instance1)
self.mount_share(location, ssh_client_inst1)
self.mount_share(location, remote_client_inst1)
self.addCleanup(self.umount_share,
ssh_client_inst1)
self.write_data(test_data, ssh_client_inst1)
remote_client_inst1)
self.write_data_to_mounted_share(test_data, remote_client_inst1)
# Read from second VM
ssh_client_inst2 = self.init_ssh(instance2)
if not CONF.share.override_ip_for_nfs_access or self.use_ipv6:
remote_client_inst2 = self.init_remote_client(instance2)
if not CONF.share.override_ip_for_nfs_access or self.ipv6_enabled:
self.provide_access_to_auxiliary_instance(instance2)
self.mount_share(location, ssh_client_inst2)
self.mount_share(location, remote_client_inst2)
self.addCleanup(self.umount_share,
ssh_client_inst2)
data = self.read_data(ssh_client_inst2)
remote_client_inst2)
data = self.read_data_from_mounted_share(remote_client_inst2)
self.assertEqual(test_data, data)
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@ -425,6 +204,10 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
raise self.skipException("Only NFS protocol supported "
"at this moment.")
if self.ipv6_enabled:
raise self.skipException("Share Migration using IPv6 is not "
"supported at this moment.")
pools = self.shares_admin_v2_client.list_pools(detail=True)['pools']
if len(pools) < 2:
@ -448,29 +231,29 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
dest_pool = dest_pool['name']
ssh_client = self.init_ssh(instance)
remote_client = self.init_remote_client(instance)
self.provide_access_to_auxiliary_instance(instance)
self.mount_share(exports[0], ssh_client)
self.mount_share(exports[0], remote_client)
ssh_client.exec_command("sudo mkdir -p /mnt/f1")
ssh_client.exec_command("sudo mkdir -p /mnt/f2")
ssh_client.exec_command("sudo mkdir -p /mnt/f3")
ssh_client.exec_command("sudo mkdir -p /mnt/f4")
ssh_client.exec_command("sudo mkdir -p /mnt/f1/ff1")
ssh_client.exec_command("sleep 1")
ssh_client.exec_command(
remote_client.exec_command("sudo mkdir -p /mnt/f1")
remote_client.exec_command("sudo mkdir -p /mnt/f2")
remote_client.exec_command("sudo mkdir -p /mnt/f3")
remote_client.exec_command("sudo mkdir -p /mnt/f4")
remote_client.exec_command("sudo mkdir -p /mnt/f1/ff1")
remote_client.exec_command("sleep 1")
remote_client.exec_command(
"sudo dd if=/dev/zero of=/mnt/f1/1m1.bin bs=1M count=1")
ssh_client.exec_command(
remote_client.exec_command(
"sudo dd if=/dev/zero of=/mnt/f2/1m2.bin bs=1M count=1")
ssh_client.exec_command(
remote_client.exec_command(
"sudo dd if=/dev/zero of=/mnt/f3/1m3.bin bs=1M count=1")
ssh_client.exec_command(
remote_client.exec_command(
"sudo dd if=/dev/zero of=/mnt/f4/1m4.bin bs=1M count=1")
ssh_client.exec_command(
remote_client.exec_command(
"sudo dd if=/dev/zero of=/mnt/f1/ff1/1m5.bin bs=1M count=1")
ssh_client.exec_command("sudo chmod -R 555 /mnt/f3")
ssh_client.exec_command("sudo chmod -R 777 /mnt/f4")
remote_client.exec_command("sudo chmod -R 555 /mnt/f3")
remote_client.exec_command("sudo chmod -R 777 /mnt/f4")
task_state = (constants.TASK_STATE_DATA_COPYING_COMPLETED
if force_host_assisted
@ -482,10 +265,10 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
if force_host_assisted:
self.assertRaises(
exceptions.SSHExecCommandFailed,
ssh_client.exec_command,
remote_client.exec_command,
"dd if=/dev/zero of=/mnt/f1/1m6.bin bs=1M count=1")
self.umount_share(ssh_client)
self.umount_share(remote_client)
self.share = self.migration_complete(self.share['id'], dest_pool)
@ -496,11 +279,11 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
self.assertEqual(constants.TASK_STATE_MIGRATION_SUCCESS,
self.share['task_state'])
self.mount_share(new_exports[0], ssh_client)
self.mount_share(new_exports[0], remote_client)
output = ssh_client.exec_command("ls -lRA --ignore=lost+found /mnt")
output = remote_client.exec_command("ls -lRA --ignore=lost+found /mnt")
self.umount_share(ssh_client)
self.umount_share(remote_client)
self.assertIn('1m1.bin', output)
self.assertIn('1m2.bin', output)
@ -508,21 +291,6 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
self.assertIn('1m4.bin', output)
self.assertIn('1m5.bin', output)
def _get_user_export_locations(self, share=None, snapshot=None,
error_on_invalid_ip_version=False):
locations = None
if share:
locations = self._get_share_export_locations(share)
elif snapshot:
locations = self._get_snapshot_export_locations(snapshot)
self.assertNotEmpty(locations)
locations = self._get_export_locations_according_to_ip_version(
locations, error_on_invalid_ip_version)
self.assertNotEmpty(locations)
return locations
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@testtools.skipUnless(
CONF.share.run_snapshot_tests, "Snapshot tests are disabled.")
@ -540,7 +308,7 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
self.addCleanup(self.servers_client.delete_server, instance['id'])
# 3 - SSH to UVM, ok, connected
ssh_client = self.init_ssh(instance)
remote_client = self.init_remote_client(instance)
# 4 - Provide RW access to S1, ok, provided
self.provide_access_to_auxiliary_instance(instance, parent_share)
@ -548,20 +316,20 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
# 5 - Try mount S1 to UVM, ok, mounted
user_export_location = self._get_user_export_locations(parent_share)[0]
parent_share_dir = "/mnt/parent"
ssh_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
remote_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
self.mount_share(user_export_location, ssh_client, parent_share_dir)
self.addCleanup(self.umount_share, ssh_client, parent_share_dir)
self.mount_share(user_export_location, remote_client, parent_share_dir)
self.addCleanup(self.umount_share, remote_client, parent_share_dir)
# 6 - Create "file1", ok, created
ssh_client.exec_command("sudo touch %s/file1" % parent_share_dir)
remote_client.exec_command("sudo touch %s/file1" % parent_share_dir)
# 7 - Create snapshot SS1 from S1, ok, created
snapshot = self._create_snapshot(parent_share['id'])
# 8 - Create "file2" in share S1 - ok, created. We expect that
# snapshot will not contain any data created after snapshot creation.
ssh_client.exec_command("sudo touch %s/file2" % parent_share_dir)
remote_client.exec_command("sudo touch %s/file2" % parent_share_dir)
# 9 - Create share S2 from SS1, ok, created
child_share = self.create_share(snapshot_id=snapshot["id"])
@ -570,37 +338,40 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
# did not get access rules from parent share.
user_export_location = self._get_user_export_locations(child_share)[0]
child_share_dir = "/mnt/child"
ssh_client.exec_command("sudo mkdir -p %s" % child_share_dir)
remote_client.exec_command("sudo mkdir -p %s" % child_share_dir)
self.assertRaises(
exceptions.SSHExecCommandFailed,
self.mount_share,
user_export_location, ssh_client, child_share_dir,
user_export_location, remote_client, child_share_dir,
)
# 11 - Provide RW access to S2, ok, provided
self.provide_access_to_auxiliary_instance(instance, child_share)
# 12 - Try mount S2, ok, mounted
self.mount_share(user_export_location, ssh_client, child_share_dir)
self.addCleanup(self.umount_share, ssh_client, child_share_dir)
self.mount_share(user_export_location, remote_client, child_share_dir)
self.addCleanup(self.umount_share, remote_client, child_share_dir)
# 13 - List files on S2, only "file1" exists
output = ssh_client.exec_command("sudo ls -lRA %s" % child_share_dir)
output = remote_client.exec_command(
"sudo ls -lRA %s" % child_share_dir)
self.assertIn('file1', output)
self.assertNotIn('file2', output)
# 14 - Create file3 on S2, ok, file created
ssh_client.exec_command("sudo touch %s/file3" % child_share_dir)
remote_client.exec_command("sudo touch %s/file3" % child_share_dir)
# 15 - List files on S1, two files exist - "file1" and "file2"
output = ssh_client.exec_command("sudo ls -lRA %s" % parent_share_dir)
output = remote_client.exec_command(
"sudo ls -lRA %s" % parent_share_dir)
self.assertIn('file1', output)
self.assertIn('file2', output)
self.assertNotIn('file3', output)
# 16 - List files on S2, two files exist - "file1" and "file3"
output = ssh_client.exec_command("sudo ls -lRA %s" % child_share_dir)
output = remote_client.exec_command(
"sudo ls -lRA %s" % child_share_dir)
self.assertIn('file1', output)
self.assertNotIn('file2', output)
self.assertIn('file3', output)
@ -625,7 +396,7 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
self.addCleanup(self.servers_client.delete_server, instance['id'])
# 3 - SSH to UVM, ok, connected
ssh_client = self.init_ssh(instance)
remote_client = self.init_remote_client(instance)
# 4 - Provide RW access to S1, ok, provided
self.provide_access_to_auxiliary_instance(instance, parent_share)
@ -634,21 +405,21 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
user_export_location = self._get_user_export_locations(parent_share)[0]
parent_share_dir = "/mnt/parent"
snapshot_dir = "/mnt/snapshot_dir"
ssh_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
ssh_client.exec_command("sudo mkdir -p %s" % snapshot_dir)
remote_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
remote_client.exec_command("sudo mkdir -p %s" % snapshot_dir)
self.mount_share(user_export_location, ssh_client, parent_share_dir)
self.addCleanup(self.umount_share, ssh_client, parent_share_dir)
self.mount_share(user_export_location, remote_client, parent_share_dir)
self.addCleanup(self.umount_share, remote_client, parent_share_dir)
# 6 - Create "file1", ok, created
ssh_client.exec_command("sudo touch %s/file1" % parent_share_dir)
remote_client.exec_command("sudo touch %s/file1" % parent_share_dir)
# 7 - Create snapshot SS1 from S1, ok, created
snapshot = self._create_snapshot(parent_share['id'])
# 8 - Create "file2" in share S1 - ok, created. We expect that
# snapshot will not contain any data created after snapshot creation.
ssh_client.exec_command("sudo touch %s/file2" % parent_share_dir)
remote_client.exec_command("sudo touch %s/file2" % parent_share_dir)
# 9 - Allow access to SS1
self.provide_access_to_auxiliary_instance(instance, snapshot=snapshot)
@ -656,45 +427,45 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
# 10 - Mount SS1
user_export_location = self._get_user_export_locations(
snapshot=snapshot)[0]
self.mount_share(user_export_location, ssh_client, snapshot_dir)
self.addCleanup(self.umount_share, ssh_client, snapshot_dir)
self.mount_share(user_export_location, remote_client, snapshot_dir)
self.addCleanup(self.umount_share, remote_client, snapshot_dir)
# 11 - List files on SS1, only "file1" exists
# NOTE(lseki): using ls without recursion to avoid permission denied
# error while listing lost+found directory on LVM volumes
output = ssh_client.exec_command("sudo ls -lA %s" % snapshot_dir)
output = remote_client.exec_command("sudo ls -lA %s" % snapshot_dir)
self.assertIn('file1', output)
self.assertNotIn('file2', output)
# 12 - Try to create a file on SS1, should fail
self.assertRaises(
exceptions.SSHExecCommandFailed,
ssh_client.exec_command,
remote_client.exec_command,
"sudo touch %s/file3" % snapshot_dir)
class TestShareBasicOpsNFS(ShareBasicOpsBase):
protocol = "nfs"
def mount_share(self, location, ssh_client, target_dir=None):
def mount_share(self, location, remote_client, target_dir=None):
self._ping_export_location(location, ssh_client)
self._ping_host_from_export_location(location, remote_client)
target_dir = target_dir or "/mnt"
ssh_client.exec_command(
remote_client.exec_command(
"sudo mount -vt nfs \"%s\" %s" % (location, target_dir))
class TestShareBasicOpsCIFS(ShareBasicOpsBase):
protocol = "cifs"
def mount_share(self, location, ssh_client, target_dir=None):
def mount_share(self, location, remote_client, target_dir=None):
self._ping_export_location(location, ssh_client)
self._ping_host_from_export_location(location, remote_client)
location = location.replace("\\", "/")
target_dir = target_dir or "/mnt"
ssh_client.exec_command(
remote_client.exec_command(
"sudo mount.cifs \"%s\" %s -o guest" % (location, target_dir)
)