diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py index 5c8cbbf1..556123f4 100644 --- a/manila_tempest_tests/tests/scenario/manager_share.py +++ b/manila_tempest_tests/tests/scenario/manager_share.py @@ -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') diff --git a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py index a72d538c..32fd7355 100644 --- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py +++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py @@ -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) )