From 7145891ef89bb4179335f1cbd435e3a7c841a3df Mon Sep 17 00:00:00 2001 From: Valeriy Ponomaryov <vponomaryov@mirantis.com> Date: Fri, 10 Jun 2016 18:29:24 +0300 Subject: [PATCH] Add dummy driver Added dummy driver for ease of testing and development of REST APIs and internal manila interfaces. It can be enabled as backend in the same way as all other share drivers. But, it does not provide any resources. Also, update tempest to be able to work with share-networks when networks are defined via config and not API. CI hooks are configured to run tempest twice using both available driver modes. Where DHSS=True mode uses StandAloneNetworkPlugin as network backend. Change-Id: I9053dddfc643cb5a6602f15235b91bbaea727dbd Implements BluePrint dummy-driver --- contrib/ci/common.sh | 59 ++++ contrib/ci/post_test_hook.sh | 58 ++- contrib/ci/pre_test_hook.sh | 51 ++- manila/tests/share/drivers/dummy.py | 330 ++++++++++++++++++ manila_tempest_tests/config.py | 9 + manila_tempest_tests/tests/api/base.py | 27 +- manila_tempest_tests/tests/api/test_shares.py | 6 +- 7 files changed, 532 insertions(+), 8 deletions(-) create mode 100644 manila/tests/share/drivers/dummy.py diff --git a/contrib/ci/common.sh b/contrib/ci/common.sh index df85a3b9af..f7652c9f2d 100755 --- a/contrib/ci/common.sh +++ b/contrib/ci/common.sh @@ -74,3 +74,62 @@ function manila_wait_for_drivers_init { # its capabilities on time. sleep 10 } + +function archive_file { + # First argument is expected to be filename + local filename=$1 + + sudo gzip -9 $filename + sudo chown jenkins:jenkins $filename.gz + sudo chmod a+r $filename.gz +} + +function save_tempest_results { + # First argument is expected to be number or tempest run + + local src_dirname + local dst_dirname + + src_dirname="$BASE/new/tempest" + dst_dirname="$BASE/logs/tempest_$1" + + # 1. Create destination directory + sudo mkdir $dst_dirname + sudo chown jenkins:jenkins $dst_dirname + sudo chmod 755 $dst_dirname + + # 2. Save tempest configuration file + sudo cp $src_dirname/etc/tempest.conf $dst_dirname/tempest_conf.txt + + # 3. Save tempest log file + cp $src_dirname/tempest.log $src_dirname/tempest.txt + echo '' > $src_dirname/tempest.log + archive_file $src_dirname/tempest.txt + sudo mv $src_dirname/tempest.txt.gz $dst_dirname/tempest.txt.gz + + # 4. Save tempest testr results + + # Check for an interrupted run first + if [ -f $src_dirname/.testrepository/tmp* ]; then + sudo cat $src_dirname/.testrepository/tmp* >> $src_dirname/tempest.subunit + elif [ -f $src_dirname/.testrepository/0 ]; then + pushd $src_dirname + sudo testr last --subunit > $src_dirname/tempest.subunit + popd + fi + + if [ -f $src_dirname/tempest.subunit ]; then + sudo /usr/os-testr-env/bin/subunit2html \ + $src_dirname/tempest.subunit $src_dirname/testr_results.html + archive_file $src_dirname/tempest.subunit + sudo mv $src_dirname/tempest.subunit.gz $dst_dirname/tempest.subunit.gz + + archive_file $src_dirname/testr_results.html + sudo mv $src_dirname/testr_results.html.gz $dst_dirname/testr_results.html.gz + + # 5. Cleanup + sudo rm -rf $src_dirname/.testrepository + else + echo "No 'testr' results available for saving. File '$src_dirname/tempest.subunit' is absent." + fi +} diff --git a/contrib/ci/post_test_hook.sh b/contrib/ci/post_test_hook.sh index f37cecd2f2..7171cf4f8c 100755 --- a/contrib/ci/post_test_hook.sh +++ b/contrib/ci/post_test_hook.sh @@ -43,7 +43,9 @@ TEST_TYPE=$3 POSTGRES_ENABLED=$4 POSTGRES_ENABLED=$(trueorfalse True POSTGRES_ENABLED) -if [[ "$BACK_END_TYPE" == "multibackend" ]]; then +if [[ "$DRIVER" == "dummy" ]]; then + export BACKENDS_NAMES="ALPHA,BETA" +elif [[ "$BACK_END_TYPE" == "multibackend" ]]; then iniset $TEMPEST_CONFIG share multi_backend True iniset $TEMPEST_CONFIG share run_migration_tests $(trueorfalse True RUN_MANILA_MIGRATION_TESTS) @@ -185,6 +187,26 @@ elif [[ "$DRIVER" == "zfsonlinux" ]]; then iniset $TEMPEST_CONFIG share multitenancy_enabled False iniset $TEMPEST_CONFIG share multi_backend True iniset $TEMPEST_CONFIG share backend_replication_type 'readable' +elif [[ "$DRIVER" == "dummy" ]]; then + MANILA_TEMPEST_CONCURRENCY=24 + RUN_MANILA_CG_TESTS=True + RUN_MANILA_MANAGE_TESTS=False + iniset $TEMPEST_CONFIG share run_migration_tests False + iniset $TEMPEST_CONFIG share run_quota_tests True + iniset $TEMPEST_CONFIG share run_replication_tests False + iniset $TEMPEST_CONFIG share run_shrink_tests True + iniset $TEMPEST_CONFIG share enable_ip_rules_for_protocols 'nfs' + iniset $TEMPEST_CONFIG share enable_user_rules_for_protocols 'cifs' + iniset $TEMPEST_CONFIG share enable_cert_rules_for_protocols '' + iniset $TEMPEST_CONFIG share enable_ro_access_level_for_protocols 'nfs,cifs' + iniset $TEMPEST_CONFIG share build_timeout 180 + iniset $TEMPEST_CONFIG share share_creation_retry_number 0 + iniset $TEMPEST_CONFIG share capability_storage_protocol 'NFS_CIFS' + iniset $TEMPEST_CONFIG share enable_protocols 'nfs,cifs' + iniset $TEMPEST_CONFIG share suppress_errors_in_cleanup False + iniset $TEMPEST_CONFIG share multitenancy_enabled True + iniset $TEMPEST_CONFIG share create_networks_when_multitenancy_enabled False + iniset $TEMPEST_CONFIG share multi_backend True fi # Enable consistency group tests @@ -213,3 +235,37 @@ manila_wait_for_drivers_init $MANILA_CONF echo "Running tempest manila test suites" sudo -H -u jenkins tox -eall-plugin $MANILA_TESTS -- --concurrency=$MANILA_TEMPEST_CONCURRENCY +RETVAL=$? + +if [[ "$DRIVER" == "dummy" ]]; then + save_tempest_results 1 + echo "First tempest run (DHSS=True) returned '$RETVAL'" + iniset $TEMPEST_CONFIG share backend_names "GAMMA,DELTA" + + # NOTE(vponomaryov): enable migration tests when its support added to + # dummy driver. + iniset $TEMPEST_CONFIG share run_migration_tests False + iniset $TEMPEST_CONFIG share run_manage_unmanage_tests True + iniset $TEMPEST_CONFIG share run_manage_unmanage_snapshot_tests True + iniset $TEMPEST_CONFIG share run_replication_tests True + iniset $TEMPEST_CONFIG share multitenancy_enabled False + iniset $TEMPEST_CONFIG share backend_replication_type 'readable' + + # Change driver mode for default share type to make tempest use + # DHSS=False backends. + source $BASE/new/devstack/openrc admin demo + manila type-key default set driver_handles_share_servers=False + + echo "Running tempest manila test suites for DHSS=False mode" + sudo -H -u jenkins tox -eall-plugin $MANILA_TESTS -- --concurrency=$MANILA_TEMPEST_CONCURRENCY + RETVAL2=$? + save_tempest_results 2 + + # Exit with last code if first succeeded else exit with first error code + if [[ "$RETVAL" == "0" ]]; then + RETVAL=$RETVAL2 + fi + + echo "Second tempest run (DHSS=False) returned '$RETVAL2'" +fi +exit $RETVAL diff --git a/contrib/ci/pre_test_hook.sh b/contrib/ci/pre_test_hook.sh index 111a515757..f30406b9e7 100755 --- a/contrib/ci/pre_test_hook.sh +++ b/contrib/ci/pre_test_hook.sh @@ -75,6 +75,55 @@ if [[ "$DRIVER" == "generic" ]]; then elif [[ "$DRIVER" == "windows" ]]; then MANILA_SERVICE_IMAGE_ENABLED=True echo "SHARE_DRIVER=manila.share.drivers.windows.windows_smb_driver.WindowsSMBDriver" >> $localrc_path +elif [[ "$DRIVER" == "dummy" ]]; then + driver_path="manila.tests.share.drivers.dummy.DummyDriver" + echo "MANILA_SERVICE_IMAGE_ENABLED=False" >> $localrc_path + echo "SHARE_DRIVER=$driver_path" >> $localrc_path + echo "SUPPRESS_ERRORS_IN_CLEANUP=False" >> $localrc_path + echo "MANILA_REPLICA_STATE_UPDATE_INTERVAL=10" >> $localrc_path + echo "MANILA_ENABLED_BACKENDS=alpha,beta,gamma,delta" >> $localrc_path + echo "MANILA_CONFIGURE_GROUPS=alpha,beta,gamma,delta,membernet,adminnet" >> $localrc_path + + echo "MANILA_OPTGROUP_alpha_share_driver=$driver_path" >> $localrc_path + echo "MANILA_OPTGROUP_alpha_driver_handles_share_servers=True" >> $localrc_path + echo "MANILA_OPTGROUP_alpha_share_backend_name=ALPHA" >> $localrc_path + echo "MANILA_OPTGROUP_alpha_network_config_group=membernet" >> $localrc_path + echo "MANILA_OPTGROUP_alpha_admin_network_config_group=adminnet" >> $localrc_path + + echo "MANILA_OPTGROUP_beta_share_driver=$driver_path" >> $localrc_path + echo "MANILA_OPTGROUP_beta_driver_handles_share_servers=True" >> $localrc_path + echo "MANILA_OPTGROUP_beta_share_backend_name=BETA" >> $localrc_path + echo "MANILA_OPTGROUP_beta_network_config_group=membernet" >> $localrc_path + echo "MANILA_OPTGROUP_beta_admin_network_config_group=adminnet" >> $localrc_path + + echo "MANILA_OPTGROUP_gamma_share_driver=$driver_path" >> $localrc_path + echo "MANILA_OPTGROUP_gamma_driver_handles_share_servers=False" >> $localrc_path + echo "MANILA_OPTGROUP_gamma_share_backend_name=GAMMA" >> $localrc_path + echo "MANILA_OPTGROUP_gamma_replication_domain=DUMMY_DOMAIN" >> $localrc_path + + echo "MANILA_OPTGROUP_delta_share_driver=$driver_path" >> $localrc_path + echo "MANILA_OPTGROUP_delta_driver_handles_share_servers=False" >> $localrc_path + echo "MANILA_OPTGROUP_delta_share_backend_name=DELTA" >> $localrc_path + echo "MANILA_OPTGROUP_delta_replication_domain=DUMMY_DOMAIN" >> $localrc_path + + echo "MANILA_OPTGROUP_membernet_network_api_class=manila.network.standalone_network_plugin.StandaloneNetworkPlugin" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_gateway=10.0.0.1" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_mask=24" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_network_type=vlan" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_segmentation_id=1010" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_allowed_ip_ranges=10.0.0.10-10.0.0.209" >> $localrc_path + echo "MANILA_OPTGROUP_membernet_standalone_network_plugin_ip_version=4" >> $localrc_path + + echo "MANILA_OPTGROUP_adminnet_network_api_class=manila.network.standalone_network_plugin.StandaloneNetworkPlugin" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_gateway=11.0.0.1" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_mask=24" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_network_type=vlan" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_segmentation_id=1011" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_allowed_ip_ranges=11.0.0.10-11.0.0.19,11.0.0.30-11.0.0.39,11.0.0.50-11.0.0.199" >> $localrc_path + echo "MANILA_OPTGROUP_adminnet_standalone_network_plugin_ip_version=4" >> $localrc_path + + export MANILA_TEMPEST_CONCURRENCY=24 + elif [[ "$DRIVER" == "lvm" ]]; then echo "SHARE_DRIVER=manila.share.drivers.lvm.LVMShareDriver" >> $localrc_path echo "SHARE_BACKING_FILE_SIZE=32000M" >> $localrc_path @@ -98,7 +147,7 @@ echo 'ENABLE_ISOLATED_METADATA=True' >> $localrc_path echo "TEMPEST_USE_TEST_ACCOUNTS=True" >> $localrc_path echo "TEMPEST_ALLOW_TENANT_ISOLATION=False" >> $localrc_path -echo "TEMPEST_CONCURRENCY=8" >> $localrc_path +echo "TEMPEST_CONCURRENCY=${MANILA_TEMPEST_CONCURRENCY:-8}" >> $localrc_path # Go to Tempest dir and checkout stable commit to avoid possible # incompatibilities for plugin stored in Manila repo. diff --git a/manila/tests/share/drivers/dummy.py b/manila/tests/share/drivers/dummy.py new file mode 100644 index 0000000000..4d1b0a8e24 --- /dev/null +++ b/manila/tests/share/drivers/dummy.py @@ -0,0 +1,330 @@ +# Copyright 2016 Mirantis inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Dummy share driver for testing Manila APIs and other interfaces. + +This driver simulates support of: +- Both available driver modes: DHSS=True/False +- NFS and CIFS protocols +- IP access for NFS shares and USER access for CIFS shares +- CIFS shares in DHSS=True driver mode +- Creation and deletion of share snapshots +- Share replication (readable) +- Consistency groups +- Resize of a share (extend/shrink) + +""" + +from oslo_log import log + +from manila.common import constants +from manila import exception +from manila.i18n import _ +from manila.share import driver +from manila.share import utils as share_utils + +LOG = log.getLogger(__name__) + + +class DummyDriver(driver.ShareDriver): + """Dummy share driver that implements all share driver interfaces.""" + + def __init__(self, *args, **kwargs): + """Do initialization.""" + super(self.__class__, self).__init__([False, True], *args, **kwargs) + self.private_storage = kwargs.get('private_storage') + self.backend_name = self.configuration.safe_get( + "share_backend_name") or "DummyDriver" + + def _get_share_name(self, share): + return "share_%(s_id)s_%(si_id)s" % { + "s_id": share["share_id"].replace("-", "_"), + "si_id": share["id"].replace("-", "_")} + + def _get_snapshot_name(self, snapshot): + return "snapshot_%(s_id)s_%(si_id)s" % { + "s_id": snapshot["snapshot_id"].replace("-", "_"), + "si_id": snapshot["id"].replace("-", "_")} + + def _generate_export_locations(self, mountpoint, share_server=None): + details = share_server["backend_details"] if share_server else { + "primary_public_ip": "10.0.0.10", + "secondary_public_ip": "10.0.0.20", + "service_ip": "11.0.0.11", + } + return [ + { + "path": "%(ip)s:%(mp)s" % {"ip": ip, "mp": mountpoint}, + "metadata": { + "preferred": preferred, + }, + "is_admin_only": is_admin_only, + } for ip, is_admin_only, preferred in ( + (details["primary_public_ip"], False, True), + (details["secondary_public_ip"], False, False), + (details["service_ip"], True, False)) + ] + + def _create_share(self, share, share_server=None): + share_proto = share["share_proto"] + if share_proto not in ("NFS", "CIFS"): + msg = _("Unsupported share protocol provided - %s.") % share_proto + raise exception.InvalidShareAccess(reason=msg) + + share_name = self._get_share_name(share) + mountpoint = "/path/to/fake/share/%s" % share_name + self.private_storage.update( + share["id"], { + "fake_provider_share_name": share_name, + "fake_provider_location": mountpoint, + } + ) + return self._generate_export_locations( + mountpoint, share_server=share_server) + + def create_share(self, context, share, share_server=None): + """Is called to create share.""" + return self._create_share(share, share_server=share_server) + + def create_share_from_snapshot(self, context, share, snapshot, + share_server=None): + """Is called to create share from snapshot.""" + return self._create_share(share, share_server=share_server) + + def _create_snapshot(self, snapshot): + snapshot_name = self._get_snapshot_name(snapshot) + self.private_storage.update( + snapshot["id"], { + "fake_provider_snapshot_name": snapshot_name, + } + ) + return {"provider_location": snapshot_name} + + def create_snapshot(self, context, snapshot, share_server=None): + """Is called to create snapshot.""" + return self._create_snapshot(snapshot) + + def delete_share(self, context, share, share_server=None): + """Is called to remove share.""" + self.private_storage.delete(share["id"]) + + def delete_snapshot(self, context, snapshot, share_server=None): + """Is called to remove snapshot.""" + self.private_storage.delete(snapshot["id"]) + + def get_pool(self, share): + """Return pool name where the share resides on.""" + pool_name = share_utils.extract_host(share["host"], level="pool") + return pool_name + + def ensure_share(self, context, share, share_server=None): + """Invoked to ensure that share is exported.""" + + def update_access(self, context, share, access_rules, add_rules, + delete_rules, share_server=None): + """Update access rules for given share.""" + for rule in add_rules + access_rules: + share_proto = share["share_proto"].lower() + access_type = rule["access_type"].lower() + if not ( + (share_proto == "nfs" and access_type == "ip") or + (share_proto == "cifs" and access_type == "user")): + msg = _("Unsupported '%(access_type)s' access type provided " + "for '%(share_proto)s' share protocol.") % { + "access_type": access_type, "share_proto": share_proto} + raise exception.InvalidShareAccess(reason=msg) + + def do_setup(self, context): + """Any initialization the share driver does while starting.""" + + def manage_existing(self, share, driver_options): + """Brings an existing share under Manila management.""" + return {"size": 1, "export_locations": self._create_share(share)} + + def unmanage(self, share): + """Removes the specified share from Manila management.""" + + def manage_existing_snapshot(self, snapshot, driver_options): + """Brings an existing snapshot under Manila management.""" + self._create_snapshot(snapshot) + return {"size": 1, "provider_location": snapshot["provider_location"]} + + def unmanage_snapshot(self, snapshot): + """Removes the specified snapshot from Manila management.""" + + def extend_share(self, share, new_size, share_server=None): + """Extends size of existing share.""" + + def shrink_share(self, share, new_size, share_server=None): + """Shrinks size of existing share.""" + + def get_network_allocations_number(self): + """Returns number of network allocations for creating VIFs.""" + return 2 + + def get_admin_network_allocations_number(self): + return 1 + + def _setup_server(self, network_info, metadata=None): + """Sets up and configures share server with given network parameters. + + Redefine it within share driver when it is going to handle share + servers. + """ + server_details = { + "primary_public_ip": network_info[ + "network_allocations"][0]["ip_address"], + "secondary_public_ip": network_info[ + "network_allocations"][1]["ip_address"], + "service_ip": network_info[ + "admin_network_allocations"][0]["ip_address"], + "username": "fake_username", + } + return server_details + + def _teardown_server(self, server_details, security_services=None): + """Tears down share server.""" + + def _get_pools_info(self): + pools = [{ + "pool_name": "fake_pool_for_%s" % self.backend_name, + "total_capacity_gb": 1230.0, + "free_capacity_gb": 1210.0, + "reserved_percentage": self.configuration.reserved_share_percentage + }] + if self.configuration.replication_domain: + pools[0]["replication_type"] = "readable" + return pools + + def _update_share_stats(self, data=None): + """Retrieve stats info from share group.""" + data = { + "share_backend_name": self.backend_name, + "storage_protocol": "NFS_CIFS", + "reserved_percentage": + self.configuration.reserved_share_percentage, + "consistency_group_support": "pool", + "snapshot_support": True, + "driver_name": "Dummy", + "pools": self._get_pools_info(), + } + if self.configuration.replication_domain: + data["replication_type"] = "readable" + super(self.__class__, self)._update_share_stats(data) + + def get_share_server_pools(self, share_server): + """Return list of pools related to a particular share server.""" + return [] + + def create_consistency_group(self, context, cg_dict, share_server=None): + """Create a consistency group.""" + LOG.debug( + "Successfully created dummy Consistency Group with ID: %s.", + cg_dict["id"]) + + def delete_consistency_group(self, context, cg_dict, share_server=None): + """Delete a consistency group.""" + LOG.debug( + "Successfully deleted dummy consistency group with ID %s.", + cg_dict["id"]) + + def create_cgsnapshot(self, context, snap_dict, share_server=None): + """Create a consistency group snapshot.""" + LOG.debug("Successfully created CG snapshot %s." % snap_dict["id"]) + return None, None + + def delete_cgsnapshot(self, context, snap_dict, share_server=None): + """Delete a consistency group snapshot.""" + LOG.debug("Successfully deleted CG snapshot %s." % snap_dict["id"]) + return None, None + + def create_consistency_group_from_cgsnapshot( + self, context, cg_dict, cgsnapshot_dict, share_server=None): + """Create a consistency group from a cgsnapshot.""" + LOG.debug( + ("Successfully created dummy Consistency Group (%(cg_id)s) " + "from CG snapshot (%(cg_snap_id)s)."), + {"cg_id": cg_dict["id"], "cg_snap_id": cgsnapshot_dict["id"]}) + return None, [] + + def create_replica(self, context, replica_list, new_replica, + access_rules, replica_snapshots, share_server=None): + """Replicate the active replica to a new replica on this backend.""" + replica_name = self._get_share_name(new_replica) + mountpoint = "/path/to/fake/share/%s" % replica_name + self.private_storage.update( + new_replica["id"], { + "fake_provider_replica_name": replica_name, + "fake_provider_location": mountpoint, + } + ) + return { + "export_locations": self._generate_export_locations( + mountpoint, share_server=share_server), + "replica_state": constants.REPLICA_STATE_IN_SYNC, + "access_rules_status": constants.STATUS_ACTIVE, + } + + def delete_replica(self, context, replica_list, replica_snapshots, + replica, share_server=None): + """Delete a replica.""" + self.private_storage.delete(replica["id"]) + + def promote_replica(self, context, replica_list, replica, access_rules, + share_server=None): + """Promote a replica to 'active' replica state.""" + return_replica_list = [] + for r in replica_list: + if r["id"] == replica["id"]: + replica_state = constants.REPLICA_STATE_ACTIVE + else: + replica_state = constants.REPLICA_STATE_IN_SYNC + return_replica_list.append( + {"id": r["id"], "replica_state": replica_state}) + return return_replica_list + + def update_replica_state(self, context, replica_list, replica, + access_rules, replica_snapshots, + share_server=None): + """Update the replica_state of a replica.""" + return constants.REPLICA_STATE_IN_SYNC + + def create_replicated_snapshot(self, context, replica_list, + replica_snapshots, share_server=None): + """Create a snapshot on active instance and update across the replicas. + + """ + return_replica_snapshots = [] + for r in replica_snapshots: + return_replica_snapshots.append( + {"id": r["id"], "status": constants.STATUS_AVAILABLE}) + return return_replica_snapshots + + def delete_replicated_snapshot(self, context, replica_list, + replica_snapshots, share_server=None): + """Delete a snapshot by deleting its instances across the replicas.""" + return_replica_snapshots = [] + for r in replica_snapshots: + return_replica_snapshots.append( + {"id": r["id"], "status": constants.STATUS_DELETED}) + return return_replica_snapshots + + def update_replicated_snapshot(self, context, replica_list, + share_replica, replica_snapshots, + replica_snapshot, share_server=None): + """Update the status of a snapshot instance that lives on a replica.""" + return { + "id": replica_snapshot["id"], "status": constants.STATUS_AVAILABLE} diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py index 7a7ee6f211..4b394c64f6 100644 --- a/manila_tempest_tests/config.py +++ b/manila_tempest_tests/config.py @@ -56,6 +56,15 @@ ShareGroup = [ help="This option used to determine backend driver type, " "multitenant driver uses share-networks, but " "single-tenant doesn't."), + cfg.BoolOpt("create_networks_when_multitenancy_enabled", + default=True, + help="This option is used only when other " + "'multitenancy_enabled' option is set to 'True'. " + "If this one is set to True, then tempest will create " + "neutron networks for each new manila share-network " + "it creates. Else it will use manila share-networks with " + "empty values (case of StandAloneNetworkPlugin and " + "NeutronSingleNetworkPlugin)."), cfg.ListOpt("enable_protocols", default=["nfs", "cifs"], help="First value of list is protocol by default, " diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py index a599196cee..79c8673cc1 100644 --- a/manila_tempest_tests/tests/api/base.py +++ b/manila_tempest_tests/tests/api/base.py @@ -203,7 +203,8 @@ class BaseSharesTest(test.BaseTestCase): # Provide share network if CONF.share.multitenancy_enabled: - if not CONF.service_available.neutron: + if (not CONF.service_available.neutron and + CONF.share.create_networks_when_multitenancy_enabled): raise cls.skipException("Neutron support is required") nc = os.networks_client share_network_id = cls.provide_share_network(client, nc, ic) @@ -235,7 +236,8 @@ class BaseSharesTest(test.BaseTestCase): os.auth_provider) cls.shares_v2_client = os.shares_v2_client if CONF.share.multitenancy_enabled: - if not CONF.service_available.neutron: + if (not CONF.service_available.neutron and + CONF.share.create_networks_when_multitenancy_enabled): raise cls.skipException("Neutron support is required") share_network_id = cls.provide_share_network( cls.shares_v2_client, os.networks_client) @@ -282,6 +284,8 @@ class BaseSharesTest(test.BaseTestCase): """ sc = shares_client + search_word = "reusable" + sn_name = "autogenerated_by_tempest_%s" % search_word if not CONF.share.multitenancy_enabled: # Assumed usage of a single-tenant driver @@ -289,13 +293,28 @@ class BaseSharesTest(test.BaseTestCase): elif sc.share_network_id: # Share-network already exists, use it share_network_id = sc.share_network_id + elif not CONF.share.create_networks_when_multitenancy_enabled: + share_network_id = None + + # Try get suitable share-network + share_networks = sc.list_share_networks_with_detail() + for sn in share_networks: + if (sn["neutron_net_id"] is None and + sn["neutron_subnet_id"] is None and + sn["name"] and search_word in sn["name"]): + share_network_id = sn["id"] + break + + # Create new share-network if one was not found + if share_network_id is None: + sn_desc = "This share-network was created by tempest" + sn = sc.create_share_network(name=sn_name, description=sn_desc) + share_network_id = sn["id"] else: net_id = subnet_id = share_network_id = None if not isolated_creds_client: # Search for networks, created in previous runs - search_word = "reusable" - sn_name = "autogenerated_by_tempest_%s" % search_word service_net_name = "share-service" networks = networks_client.list_networks() if "networks" in networks.keys(): diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py index 2acd81a8e1..f7ff194f64 100644 --- a/manila_tempest_tests/tests/api/test_shares.py +++ b/manila_tempest_tests/tests/api/test_shares.py @@ -146,8 +146,10 @@ class SharesNFSTest(base.BaseSharesTest): self.protocol, snapshot_id=snap["id"], cleanup_in_class=False) # The 'status' of the share returned by the create API must be - # the default value - 'creating'. - self.assertEqual('creating', s2['status']) + # set and have value either 'creating' or + # 'available' (if share creation is really fast as in + # case of Dummy driver). + self.assertIn(s2['status'], ('creating', 'available')) # verify share, created from snapshot get = self.shares_client.get_share(s2["id"])