Merge "Remove in-tree tempest plugin"

This commit is contained in:
Zuul
2017-12-22 13:40:44 +00:00
committed by Gerrit Code Review
121 changed files with 56 additions and 20416 deletions

View File

@@ -93,6 +93,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -106,6 +107,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -119,6 +121,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -132,6 +135,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-glusterfs
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -145,6 +149,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-glusterfs
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -158,6 +163,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-glusterfs
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -171,6 +177,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-glusterfs
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -184,6 +191,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-hdfs
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -197,6 +205,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -210,6 +219,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -223,6 +233,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -236,6 +247,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -249,6 +261,7 @@
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-image-elements
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -263,6 +276,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-ceph
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -277,6 +291,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-ceph
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -289,6 +304,7 @@
required-projects:
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -302,6 +318,7 @@
required-projects:
- openstack-infra/devstack-gate
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -316,6 +333,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-ceph
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest
@@ -330,6 +348,7 @@
- openstack-infra/devstack-gate
- openstack/devstack-plugin-ceph
- openstack/manila
- openstack/manila-tempest-plugin
- openstack/python-manilaclient
- openstack/tempest

View File

@@ -329,7 +329,7 @@ for port in ${UDP_PORTS[*]}; do
done
echo "Running tempest manila test suites"
sudo -H -u $USER tox -eall-plugin $MANILA_TESTS -- --concurrency=$MANILA_TEMPEST_CONCURRENCY
sudo -H -u $USER tox -eall -- $MANILA_TESTS --concurrency=$MANILA_TEMPEST_CONCURRENCY
RETVAL=$?
@@ -351,7 +351,7 @@ if [[ "$DRIVER" == "dummy" ]]; then
manila type-key default set driver_handles_share_servers=False
echo "Running tempest manila test suites for DHSS=False mode"
sudo -H -u $USER tox -eall-plugin $MANILA_TESTS -- --concurrency=$MANILA_TEMPEST_CONCURRENCY
sudo -H -u $USER tox -eall -- $MANILA_TESTS --concurrency=$MANILA_TEMPEST_CONCURRENCY
RETVAL2=$?
save_tempest_results 2

View File

@@ -192,6 +192,13 @@ MANILA_DATA_NODE_IP=${MANILA_DATA_NODE_IP:=$MANILA_ADMIN_NET_RANGE}
# Data Service copy validation
MANILA_DATA_COPY_CHECK_HASH=${MANILA_DATA_COPY_CHECK_HASH:=True}
MANILA_TEMPEST_PLUGIN_PATH=$DEST/manila-tempest-plugin
if [[ $TEMPEST_PLUGINS != 0 ]] ; then
TEMPEST_PLUGINS="$MANILA_TEMPEST_PLUGIN_PATH $TEMPEST_PLUGINS"
else
TEMPEST_PLUGINS=$MANILA_TEMPEST_PLUGIN_PATH
fi
# Enable manila services
# ----------------------
# We have to add Manila to enabled services for screen_it to work

View File

@@ -1,6 +0,0 @@
====================
Tempest Integration
====================
This directory contains Tempest tests to cover Manila project.

View File

@@ -1,32 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# 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.
from tempest import config
from tempest.lib.services import clients
CONF = config.CONF
class Clients(clients.ServiceClients):
"""Tempest stable service clients and loaded plugins service clients"""
def __init__(self, credentials, service=None):
"""Emulate the interface of Tempest's clients.Manager"""
# Identity settings
if CONF.identity.auth_version == 'v2':
identity_uri = CONF.identity.uri
else:
identity_uri = CONF.identity.uri_v3
super(Clients, self).__init__(credentials, identity_uri)

View File

@@ -1,85 +0,0 @@
# 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.
# Shares
STATUS_ERROR = 'error'
STATUS_AVAILABLE = 'available'
STATUS_ERROR_DELETING = 'error_deleting'
STATUS_MIGRATING = 'migrating'
TEMPEST_MANILA_PREFIX = 'tempest-manila'
# Replication
REPLICATION_STYLE_READABLE = 'readable'
REPLICATION_STYLE_WRITABLE = 'writable'
REPLICATION_STYLE_DR = 'dr'
REPLICATION_TYPE_CHOICES = (
REPLICATION_STYLE_READABLE,
REPLICATION_STYLE_WRITABLE,
REPLICATION_STYLE_DR,
)
REPLICATION_PROMOTION_CHOICES = (
REPLICATION_STYLE_READABLE,
REPLICATION_STYLE_DR,
)
REPLICATION_STATE_ACTIVE = 'active'
REPLICATION_STATE_IN_SYNC = 'in_sync'
REPLICATION_STATE_OUT_OF_SYNC = 'out_of_sync'
# Access Rules
RULE_STATE_ACTIVE = 'active'
RULE_STATE_OUT_OF_SYNC = 'out_of_sync'
RULE_STATE_ERROR = 'error'
TASK_STATE_MIGRATION_STARTING = 'migration_starting'
TASK_STATE_MIGRATION_IN_PROGRESS = 'migration_in_progress'
TASK_STATE_MIGRATION_COMPLETING = 'migration_completing'
TASK_STATE_MIGRATION_SUCCESS = 'migration_success'
TASK_STATE_MIGRATION_ERROR = 'migration_error'
TASK_STATE_MIGRATION_CANCELLED = 'migration_cancelled'
TASK_STATE_MIGRATION_DRIVER_STARTING = 'migration_driver_starting'
TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS = 'migration_driver_in_progress'
TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE = 'migration_driver_phase1_done'
TASK_STATE_DATA_COPYING_STARTING = 'data_copying_starting'
TASK_STATE_DATA_COPYING_IN_PROGRESS = 'data_copying_in_progress'
TASK_STATE_DATA_COPYING_COMPLETING = 'data_copying_completing'
TASK_STATE_DATA_COPYING_COMPLETED = 'data_copying_completed'
TASK_STATE_DATA_COPYING_CANCELLED = 'data_copying_cancelled'
TASK_STATE_DATA_COPYING_ERROR = 'data_copying_error'
# Revert to snapshot
REVERT_TO_SNAPSHOT_MICROVERSION = '2.27'
REVERT_TO_SNAPSHOT_SUPPORT = 'revert_to_snapshot_support'
STATUS_RESTORING = 'restoring'
STATUS_REVERTING = 'reverting'
STATUS_REVERTING_ERROR = 'reverting_error'
# Share groups
MIN_SHARE_GROUP_MICROVERSION = '2.31'
SHARE_GROUP_SIMPLE_KEYS = {
'id', 'name', 'links',
}
SHARE_GROUP_DETAIL_REQUIRED_KEYS = {
'id', 'name', 'description', 'created_at', 'status', 'share_types',
'project_id', 'host', 'links', 'share_group_type_id',
}
SHARE_GROUP_SNAPSHOT_SIMPLE_KEYS = {
'id', 'name', 'links',
}
SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS = {
'id', 'name', 'description', 'created_at', 'status', 'project_id',
'links', 'share_group_id', 'members',
}
SHARE_GROUP_TYPE_REQUIRED_KEYS = {
'id', 'name', 'share_types', 'is_public', 'group_specs',
}

View File

@@ -1,92 +0,0 @@
# 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.
import six
import sys
from oslo_log import log
from tempest import config
from tempest.lib.common import ssh
from tempest.lib.common.utils import test_utils
import tempest.lib.exceptions
CONF = config.CONF
LOG = log.getLogger(__name__)
def debug_ssh(function):
"""Decorator to generate extra debug info in case of ssh failure"""
def wrapper(self, *args, **kwargs):
try:
return function(self, *args, **kwargs)
except tempest.lib.exceptions.SSHTimeout:
try:
original_exception = sys.exc_info()
caller = test_utils.find_test_caller() or "not found"
if self.server:
msg = 'Caller: %s. Timeout trying to ssh to server %s'
LOG.debug(msg, caller, self.server)
if self.log_console and self.servers_client:
try:
msg = 'Console log for server %s: %s'
console_log = (
self.servers_client.get_console_output(
self.server['id'])['output'])
LOG.debug(msg, self.server['id'], console_log)
except Exception:
msg = 'Could not get console_log for server %s'
LOG.debug(msg, self.server['id'])
# re-raise the original ssh timeout exception
six.reraise(*original_exception)
finally:
# Delete the traceback to avoid circular references
_, _, trace = original_exception
del trace
return wrapper
class RemoteClient(object):
def __init__(self, ip_address, username, password=None, pkey=None,
server=None, servers_client=None):
"""Executes commands in a VM over ssh
:param ip_address: IP address to ssh to
:param username: ssh username
:param password: ssh password (optional)
:param pkey: ssh public key (optional)
:param server: server dict, used for debugging purposes
:param servers_client: servers client, used for debugging purposes
"""
self.server = server
self.servers_client = servers_client
self.log_console = CONF.compute_feature_enabled.console_output
self.ssh_client = ssh.Client(ip_address, username, password, pkey=pkey)
@debug_ssh
def exec_command(self, cmd):
# Shell options below add more clearness on failures,
# path is extended for some non-cirros guest oses (centos7)
cmd = CONF.validation.ssh_shell_prologue + " " + cmd
LOG.debug("Remote command: %s", cmd)
return self.ssh_client.exec_command(cmd)
@debug_ssh
def validate_authentication(self):
"""Validate ssh connection and authentication
This method raises an Exception when the validation fails.
"""
self.ssh_client.test_connection_auth()

View File

@@ -1,247 +0,0 @@
# Copyright 2014 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.
from __future__ import print_function
from oslo_config import cfg
service_option = cfg.BoolOpt("manila",
default=True,
help="Whether or not manila is expected to be "
"available")
share_group = cfg.OptGroup(name="share", title="Share Service Options")
ShareGroup = [
cfg.StrOpt("min_api_microversion",
default="2.0",
help="The minimum api microversion is configured to be the "
"value of the minimum microversion supported by Manila."),
cfg.StrOpt("max_api_microversion",
default="2.42",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
default="",
help="The share region name to use. If empty, the value "
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
cfg.StrOpt("catalog_type",
default="share",
help="Catalog type of the Share service."),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the share service."),
cfg.BoolOpt("multitenancy_enabled",
default=True,
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, "
"items of list show enabled protocols at all."),
cfg.ListOpt("enable_ip_rules_for_protocols",
default=["nfs", "cifs", ],
help="Selection of protocols, that should "
"be covered with ip rule tests"),
cfg.ListOpt("enable_user_rules_for_protocols",
default=[],
help="Selection of protocols, that should "
"be covered with user rule tests"),
cfg.ListOpt("enable_cert_rules_for_protocols",
default=["glusterfs", ],
help="Protocols that should be covered with cert rule tests."),
cfg.ListOpt("enable_cephx_rules_for_protocols",
default=["cephfs", ],
help="Protocols to be covered with cephx rule tests."),
cfg.StrOpt("username_for_user_rules",
default="Administrator",
help="Username, that will be used in user tests."),
cfg.ListOpt("enable_ro_access_level_for_protocols",
default=["nfs", ],
help="List of protocols to run tests with ro access level."),
# Capabilities
cfg.StrOpt("capability_storage_protocol",
deprecated_name="storage_protocol",
default="NFS_CIFS",
help="Backend protocol to target when creating volume types."),
cfg.BoolOpt("capability_snapshot_support",
help="Defines extra spec that satisfies specific back end "
"capability called 'snapshot_support' and will be used "
"for setting up custom share type. Defaults to value of "
"other config option 'run_snapshot_tests'."),
cfg.BoolOpt("capability_create_share_from_snapshot_support",
help="Defines extra spec that satisfies specific back end "
"capability called 'create_share_from_snapshot_support' "
"and will be used for setting up a custom share type. "
"Defaults to the value of run_snapshot_tests. Set it to "
"False if the driver being tested does not support "
"creating shares from snapshots."),
cfg.BoolOpt("capability_revert_to_snapshot_support",
deprecated_for_removal=True,
deprecated_reason="Redundant configuration option. Please use "
"'run_revert_to_snapshot_tests' config "
"option instead.",
help="Defines extra spec that satisfies specific back end "
"capability called 'revert_to_snapshot_support' "
"and will be used for setting up custom share type. "
"Defaults to the value of run_revert_to_snapshot_tests."),
cfg.StrOpt("capability_sg_consistent_snapshot_support",
choices=["host", "pool", None],
help="Backend capability to create consistent snapshots of "
"share group members. Will be used with creation "
"of new share group types as group spec."),
cfg.StrOpt("share_network_id",
default="",
help="Some backend drivers requires share network "
"for share creation. Share network id, that will be "
"used for shares. If not set, it won't be used."),
cfg.StrOpt("alt_share_network_id",
default="",
help="Share network id, that will be used for shares"
" in alt tenant. If not set, it won't be used"),
cfg.StrOpt("admin_share_network_id",
default="",
help="Share network id, that will be used for shares"
" in admin tenant. If not set, it won't be used"),
cfg.BoolOpt("multi_backend",
default=False,
help="Runs Manila multi-backend tests."),
cfg.ListOpt("backend_names",
default=[],
help="Names of share backends, that will be used with "
"multibackend tests. Tempest will use first two values."),
cfg.IntOpt("share_creation_retry_number",
default=0,
help="Defines number of retries for share creation. "
"It is useful to avoid failures caused by unstable "
"environment."),
cfg.IntOpt("build_interval",
default=3,
help="Time in seconds between share availability checks."),
cfg.IntOpt("build_timeout",
default=500,
help="Timeout in seconds to wait for a share to become"
"available."),
cfg.BoolOpt("suppress_errors_in_cleanup",
default=False,
help="Whether to suppress errors with clean up operation "
"or not. There are cases when we may want to skip "
"such errors and catch only test errors."),
# Switching ON/OFF test suites filtered by features
cfg.BoolOpt("run_quota_tests",
default=True,
help="Defines whether to run quota tests or not."),
cfg.BoolOpt("run_extend_tests",
default=True,
help="Defines whether to run share extend tests or not. "
"Disable this feature if used driver doesn't "
"support it."),
cfg.BoolOpt("run_shrink_tests",
default=True,
help="Defines whether to run share shrink tests or not. "
"Disable this feature if used driver doesn't "
"support it."),
cfg.BoolOpt("run_snapshot_tests",
default=True,
help="Defines whether to run tests that use share snapshots "
"or not. Disable this feature if used driver doesn't "
"support it."),
cfg.BoolOpt("run_revert_to_snapshot_tests",
default=False,
help="Defines whether to run tests that revert shares "
"to snapshots or not. Enable this feature if used "
"driver supports it."),
cfg.BoolOpt("run_share_group_tests",
default=True,
deprecated_name="run_consistency_group_tests",
help="Defines whether to run share group tests or not."),
cfg.BoolOpt("run_replication_tests",
default=False,
help="Defines whether to run replication tests or not. "
"Enable this feature if the driver is configured "
"for replication."),
cfg.BoolOpt("run_multiple_share_replicas_tests",
default=True,
help="Defines whether to run multiple replicas creation test "
"or not. Enable this if the driver can create more than "
"one replica for a share."),
cfg.BoolOpt("run_host_assisted_migration_tests",
deprecated_name="run_migration_tests",
default=False,
help="Enable or disable host-assisted migration tests."),
cfg.BoolOpt("run_driver_assisted_migration_tests",
deprecated_name="run_migration_tests",
default=False,
help="Enable or disable driver-assisted migration tests."),
cfg.BoolOpt("run_migration_with_preserve_snapshots_tests",
default=False,
help="Enable or disable migration with "
"preserve_snapshots tests set to True."),
cfg.BoolOpt("run_manage_unmanage_tests",
default=False,
help="Defines whether to run manage/unmanage tests or not. "
"These test may leave orphaned resources, so be careful "
"enabling this opt."),
cfg.BoolOpt("run_manage_unmanage_snapshot_tests",
default=False,
help="Defines whether to run manage/unmanage snapshot tests "
"or not. These tests may leave orphaned resources, so be "
"careful enabling this opt."),
cfg.BoolOpt("run_mount_snapshot_tests",
default=False,
help="Enable or disable mountable snapshot tests."),
cfg.StrOpt("image_with_share_tools",
default="manila-service-image-master",
help="Image name for vm booting with nfs/smb clients tool."),
cfg.StrOpt("image_username",
default="manila",
help="Image username."),
cfg.StrOpt("image_password",
help="Image password. Should be used for "
"'image_with_share_tools' without Nova Metadata support."),
cfg.StrOpt("client_vm_flavor_ref",
default="100",
help="Flavor used for client vm in scenario tests."),
cfg.IntOpt("migration_timeout",
default=1500,
help="Time to wait for share migration before "
"timing out (seconds)."),
cfg.StrOpt("default_share_type_name",
help="Default share type name to use in tempest tests."),
cfg.StrOpt("backend_replication_type",
default='none',
choices=['none', 'writable', 'readable', 'dr'],
help="Specify the replication type supported by the backend."),
cfg.IntOpt("share_size",
default=1,
help="Default size in GB for shares created by share tests."),
]

View File

@@ -1,75 +0,0 @@
# Copyright 2015 Deutsche Telekom AG
# 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.
import os
from tempest import config
from tempest.test_discover import plugins
from manila_tempest_tests import config as config_share
class ManilaTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "manila_tempest_tests/tests"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
conf.register_opt(config_share.service_option,
group='service_available')
conf.register_group(config_share.share_group)
conf.register_opts(config_share.ShareGroup, group='share')
# NOTE(vponomaryov): Set options 'capability_snapshot_support' and
# 'capability_create_share_from_snapshot_support' to opt
# 'run_snapshot_tests' if not configured.
if conf.share.capability_snapshot_support is None:
conf.set_default(
"capability_snapshot_support",
conf.share.run_snapshot_tests,
group="share",
)
if conf.share.capability_create_share_from_snapshot_support is None:
conf.set_default(
"capability_create_share_from_snapshot_support",
conf.share.run_snapshot_tests,
group="share",
)
def get_opt_lists(self):
return [(config_share.share_group.name, config_share.ShareGroup),
('service_available', [config_share.service_option])]
def get_service_clients(self):
shares_config = config.service_client_config('share')
v1_params = {
'name': 'share_v1',
'service_version': 'share.v1',
'module_path': 'manila_tempest_tests.services.share.json',
'client_names': ['SharesClient'],
}
v2_params = {
'name': 'share_v2',
'service_version': 'share.v2',
'module_path': 'manila_tempest_tests.services.share.v2',
'client_names': ['SharesV2Client'],
}
v1_params.update(shares_config)
v2_params.update(shares_config)
return [v1_params, v2_params]

View File

@@ -1,18 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# 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.
from manila_tempest_tests.services.share import json as v1
from manila_tempest_tests.services.share.v2 import json as v2
__all__ = ['v1', 'v2']

View File

@@ -1,17 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# 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.
from manila_tempest_tests.services.share.json.shares_client import SharesClient
__all__ = ['SharesClient']

View File

@@ -1,760 +0,0 @@
# Copyright 2014 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.
import json
import time
import six
from six.moves.urllib import parse as urlparse
from tempest import config
from tempest.lib.common import rest_client
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from manila_tempest_tests import share_exceptions
CONF = config.CONF
class SharesClient(rest_client.RestClient):
"""Tempest REST client for Manila.
It handles shares and access to it in OpenStack.
"""
def __init__(self, auth_provider, **kwargs):
super(SharesClient, self).__init__(auth_provider, **kwargs)
self.share_protocol = None
if CONF.share.enable_protocols:
self.share_protocol = CONF.share.enable_protocols[0]
self.share_network_id = CONF.share.share_network_id
self.share_size = CONF.share.share_size
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, is_public=False):
metadata = metadata or {}
if name is None:
name = data_utils.rand_name("tempest-created-share")
if description is None:
description = data_utils.rand_name("tempest-created-share-desc")
if size is None:
size = self.share_size
if share_protocol is None:
share_protocol = self.share_protocol
if share_protocol is None:
raise share_exceptions.ShareProtocolNotSpecified()
post_body = {
"share": {
"share_proto": share_protocol,
"description": description,
"snapshot_id": snapshot_id,
"name": name,
"size": size,
"metadata": metadata,
"is_public": is_public,
}
}
if share_network_id:
post_body["share"]["share_network_id"] = share_network_id
if share_type_id:
post_body["share"]["share_type"] = share_type_id
body = json.dumps(post_body)
resp, body = self.post("shares", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share(self, share_id):
resp, body = self.delete("shares/%s" % share_id)
self.expected_success(202, resp.status)
return body
def manage_share(self, service_host, protocol, export_path,
share_type_id, name=None, description=None):
post_body = {
"share": {
"export_path": export_path,
"service_host": service_host,
"protocol": protocol,
"share_type": share_type_id,
"name": name,
"description": description,
}
}
body = json.dumps(post_body)
resp, body = self.post("os-share-manage", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def unmanage_share(self, share_id):
resp, body = self.post(
"os-share-unmanage/%s/unmanage" % share_id, None)
self.expected_success(202, resp.status)
return body
def list_shares(self, detailed=False, params=None):
"""Get list of shares w/o filters."""
uri = 'shares/detail' if detailed else 'shares'
uri += '?%s' % urlparse.urlencode(params) if params else ''
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_shares_with_detail(self, params=None):
"""Get detailed list of shares w/o filters."""
return self.list_shares(detailed=True, params=params)
def get_share(self, share_id):
resp, body = self.get("shares/%s" % share_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_access_rule(self, share_id, access_type="ip",
access_to="0.0.0.0", access_level=None):
post_body = {
"os-allow_access": {
"access_type": access_type,
"access_to": access_to,
"access_level": access_level,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_access_rules(self, share_id):
body = {"os-access_list": None}
resp, body = self.post("shares/%s/action" % share_id, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_access_rule(self, share_id, rule_id):
post_body = {
"os-deny_access": {
"access_id": rule_id,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def extend_share(self, share_id, new_size):
post_body = {
"os-extend": {
"new_size": new_size,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def shrink_share(self, share_id, new_size):
post_body = {
"os-shrink": {
"new_size": new_size,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def create_snapshot(self, share_id, name=None, description=None,
force=False):
if name is None:
name = data_utils.rand_name("tempest-created-share-snap")
if description is None:
description = data_utils.rand_name(
"tempest-created-share-snap-desc")
post_body = {
"snapshot": {
"name": name,
"force": force,
"description": description,
"share_id": share_id,
}
}
body = json.dumps(post_body)
resp, body = self.post("snapshots", body)
self.expected_success(202, resp.status)
return self._parse_resp(body)
def get_snapshot(self, snapshot_id):
resp, body = self.get("snapshots/%s" % snapshot_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_snapshots(self, detailed=False, params=None):
"""Get list of share snapshots w/o filters."""
uri = 'snapshots/detail' if detailed else 'snapshots'
uri += '?%s' % urlparse.urlencode(params) if params else ''
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_snapshots_with_detail(self, params=None):
"""Get detailed list of share snapshots w/o filters."""
return self.list_snapshots(detailed=True, params=params)
def delete_snapshot(self, snap_id):
resp, body = self.delete("snapshots/%s" % snap_id)
self.expected_success(202, resp.status)
return body
def wait_for_share_status(self, share_id, status):
"""Waits for a share to reach a given status."""
body = self.get_share(share_id)
share_name = body['name']
share_status = body['status']
start = int(time.time())
while share_status != status:
time.sleep(self.build_interval)
body = self.get_share(share_id)
share_status = body['status']
if share_status == status:
return
elif 'error' in share_status.lower():
raise share_exceptions.ShareBuildErrorException(
share_id=share_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share %s failed to reach %s status within '
'the required time (%s s).' %
(share_name, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def wait_for_snapshot_status(self, snapshot_id, status):
"""Waits for a snapshot to reach a given status."""
body = self.get_snapshot(snapshot_id)
snapshot_name = body['name']
snapshot_status = body['status']
start = int(time.time())
while snapshot_status != status:
time.sleep(self.build_interval)
body = self.get_snapshot(snapshot_id)
snapshot_status = body['status']
if 'error' in snapshot_status:
raise share_exceptions.SnapshotBuildErrorException(
snapshot_id=snapshot_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share Snapshot %s failed to reach %s status '
'within the required time (%s s).' %
(snapshot_name, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def wait_for_access_rule_status(self, share_id, rule_id, status):
"""Waits for an access rule to reach a given status."""
rule_status = "new"
start = int(time.time())
while rule_status != status:
time.sleep(self.build_interval)
rules = self.list_access_rules(share_id)
for rule in rules:
if rule["id"] in rule_id:
rule_status = rule['state']
break
if 'error' in rule_status:
raise share_exceptions.AccessRuleBuildErrorException(
rule_id=rule_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share Access Rule %s failed to reach %s status '
'within the required time (%s s).' %
(rule_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def default_quotas(self, tenant_id):
resp, body = self.get("os-quota-sets/%s/defaults" % tenant_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def show_quotas(self, tenant_id, user_id=None):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def reset_quotas(self, tenant_id, user_id=None):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
def update_quotas(self, tenant_id, user_id=None, shares=None,
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
share_networks=None, force=True):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
put_body = {"tenant_id": tenant_id}
if force:
put_body["force"] = "true"
if shares is not None:
put_body["shares"] = shares
if snapshots is not None:
put_body["snapshots"] = snapshots
if gigabytes is not None:
put_body["gigabytes"] = gigabytes
if snapshot_gigabytes is not None:
put_body["snapshot_gigabytes"] = snapshot_gigabytes
if share_networks is not None:
put_body["share_networks"] = share_networks
put_body = json.dumps({"quota_set": put_body})
resp, body = self.put(uri, put_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_limits(self):
resp, body = self.get("limits")
self.expected_success(200, resp.status)
return self._parse_resp(body)
def is_resource_deleted(self, *args, **kwargs):
"""Verifies whether provided resource deleted or not.
:param kwargs: dict with expected keys 'share_id', 'snapshot_id',
:param kwargs: 'sn_id', 'ss_id', 'vt_id' and 'server_id'
:raises share_exceptions.InvalidResource
"""
if "share_id" in kwargs:
if "rule_id" in kwargs:
rule_id = kwargs.get("rule_id")
share_id = kwargs.get("share_id")
rules = self.list_access_rules(share_id)
for rule in rules:
if rule["id"] == rule_id:
return False
return True
else:
return self._is_resource_deleted(
self.get_share, kwargs.get("share_id"))
elif "snapshot_id" in kwargs:
return self._is_resource_deleted(
self.get_snapshot, kwargs.get("snapshot_id"))
elif "sn_id" in kwargs:
return self._is_resource_deleted(
self.get_share_network, kwargs.get("sn_id"))
elif "ss_id" in kwargs:
return self._is_resource_deleted(
self.get_security_service, kwargs.get("ss_id"))
elif "vt_id" in kwargs:
return self._is_resource_deleted(
self.get_volume_type, kwargs.get("vt_id"))
elif "st_id" in kwargs:
return self._is_resource_deleted(
self.get_share_type, kwargs.get("st_id"))
elif "server_id" in kwargs:
return self._is_resource_deleted(
self.show_share_server, kwargs.get("server_id"))
else:
raise share_exceptions.InvalidResource(
message=six.text_type(kwargs))
def _is_resource_deleted(self, func, res_id):
try:
res = func(res_id)
except exceptions.NotFound:
return True
if res.get('status') in ['error_deleting', 'error']:
# Resource has "error_deleting" status and can not be deleted.
resource_type = func.__name__.split('_', 1)[-1]
raise share_exceptions.ResourceReleaseFailed(
res_type=resource_type, res_id=res_id)
return False
def wait_for_resource_deletion(self, *args, **kwargs):
"""Waits for a resource to be deleted."""
start_time = int(time.time())
while True:
if self.is_resource_deleted(*args, **kwargs):
return
if int(time.time()) - start_time >= self.build_timeout:
raise exceptions.TimeoutException
time.sleep(self.build_interval)
def list_extensions(self):
resp, extensions = self.get("extensions")
self.expected_success(200, resp.status)
return self._parse_resp(extensions)
def update_share(self, share_id, name=None, desc=None, is_public=None):
body = {"share": {}}
if name is not None:
body["share"].update({"display_name": name})
if desc is not None:
body["share"].update({"display_description": desc})
if is_public is not None:
body["share"].update({"is_public": is_public})
body = json.dumps(body)
resp, body = self.put("shares/%s" % share_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def rename_snapshot(self, snapshot_id, name, desc=None):
body = {"snapshot": {"display_name": name}}
if desc is not None:
body["snapshot"].update({"display_description": desc})
body = json.dumps(body)
resp, body = self.put("snapshots/%s" % snapshot_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def reset_state(self, s_id, status="error", s_type="shares"):
"""Resets the state of a share or a snapshot.
status: available, error, creating, deleting, error_deleting
s_type: shares, snapshots
"""
body = {"os-reset_status": {"status": status}}
body = json.dumps(body)
resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
self.expected_success(202, resp.status)
return body
def force_delete(self, s_id, s_type="shares"):
"""Force delete share or snapshot.
s_type: shares, snapshots
"""
body = {"os-force_delete": None}
body = json.dumps(body)
resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
self.expected_success(202, resp.status)
return body
###############
def list_services(self, params=None):
"""List services."""
uri = 'os-services'
if params:
uri += '?%s' % urlparse.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def _update_metadata(self, share_id, metadata=None, method="post"):
uri = "shares/%s/metadata" % share_id
if metadata is None:
metadata = {}
post_body = {"metadata": metadata}
body = json.dumps(post_body)
if method is "post":
resp, metadata = self.post(uri, body)
if method is "put":
resp, metadata = self.put(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(metadata)
def set_metadata(self, share_id, metadata=None):
return self._update_metadata(share_id, metadata)
def update_all_metadata(self, share_id, metadata=None):
return self._update_metadata(share_id, metadata, method="put")
def delete_metadata(self, share_id, key):
resp, body = self.delete("shares/%s/metadata/%s" % (share_id, key))
self.expected_success(200, resp.status)
return body
def get_metadata(self, share_id):
resp, body = self.get("shares/%s/metadata" % share_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def create_security_service(self, ss_type="ldap", **kwargs):
# ss_type: ldap, kerberos, active_directory
# kwargs: name, description, dns_ip, server, domain, user, password
post_body = {"type": ss_type}
post_body.update(kwargs)
body = json.dumps({"security_service": post_body})
resp, body = self.post("security-services", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_security_service(self, ss_id, **kwargs):
# ss_id - id of security-service entity
# kwargs: dns_ip, server, domain, user, password, name, description
# for 'active' status can be changed
# only 'name' and 'description' fields
body = json.dumps({"security_service": kwargs})
resp, body = self.put("security-services/%s" % ss_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_security_service(self, ss_id):
resp, body = self.get("security-services/%s" % ss_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_security_services(self, detailed=False, params=None):
uri = "security-services"
if detailed:
uri += '/detail'
if params:
uri += "?%s" % urlparse.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_security_service(self, ss_id):
resp, body = self.delete("security-services/%s" % ss_id)
self.expected_success(202, resp.status)
return body
###############
def create_share_network(self, **kwargs):
# kwargs: name, description
# + for neutron: neutron_net_id, neutron_subnet_id
body = json.dumps({"share_network": kwargs})
resp, body = self.post("share-networks", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_network(self, sn_id, **kwargs):
# kwargs: name, description
# + for neutron: neutron_net_id, neutron_subnet_id
body = json.dumps({"share_network": kwargs})
resp, body = self.put("share-networks/%s" % sn_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_network(self, sn_id):
resp, body = self.get("share-networks/%s" % sn_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_networks(self):
resp, body = self.get("share-networks")
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_networks_with_detail(self, params=None):
"""List the details of all shares."""
uri = "share-networks/detail"
if params:
uri += "?%s" % urlparse.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_network(self, sn_id):
resp, body = self.delete("share-networks/%s" % sn_id)
self.expected_success(202, resp.status)
return body
###############
def _map_security_service_and_share_network(self, sn_id, ss_id,
action="add"):
# sn_id: id of share_network_entity
# ss_id: id of security service entity
# action: add, remove
data = {
"%s_security_service" % action: {
"security_service_id": ss_id,
}
}
body = json.dumps(data)
resp, body = self.post("share-networks/%s/action" % sn_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def add_sec_service_to_share_network(self, sn_id, ss_id):
body = self._map_security_service_and_share_network(sn_id, ss_id)
return body
def remove_sec_service_from_share_network(self, sn_id, ss_id):
body = self._map_security_service_and_share_network(
sn_id, ss_id, "remove")
return body
def list_sec_services_for_share_network(self, sn_id):
resp, body = self.get("security-services?share_network_id=%s" % sn_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def list_share_types(self, params=None):
uri = 'types'
if params is not None:
uri += '?%s' % urlparse.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_share_type(self, name, is_public=True, **kwargs):
post_body = {
'name': name,
'extra_specs': kwargs.get('extra_specs'),
'os-share-type-access:is_public': is_public,
}
post_body = json.dumps({'share_type': post_body})
resp, body = self.post('types', post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_type(self, share_type_id):
resp, body = self.delete("types/%s" % share_type_id)
self.expected_success(202, resp.status)
return body
def get_share_type(self, share_type_id):
resp, body = self.get("types/%s" % share_type_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def add_access_to_share_type(self, share_type_id, project_id):
uri = 'types/%s/action' % share_type_id
post_body = {'project': project_id}
post_body = json.dumps({'addProjectAccess': post_body})
resp, body = self.post(uri, post_body)
self.expected_success(202, resp.status)
return body
def remove_access_from_share_type(self, share_type_id, project_id):
uri = 'types/%s/action' % share_type_id
post_body = {'project': project_id}
post_body = json.dumps({'removeProjectAccess': post_body})
resp, body = self.post(uri, post_body)
self.expected_success(202, resp.status)
return body
def list_access_to_share_type(self, share_type_id):
uri = 'types/%s/os-share-type-access' % share_type_id
resp, body = self.get(uri)
# [{"share_type_id": "%st_id%", "project_id": "%project_id%"}, ]
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def create_share_type_extra_specs(self, share_type_id, extra_specs):
url = "types/%s/extra_specs" % share_type_id
post_body = json.dumps({'extra_specs': extra_specs})
resp, body = self.post(url, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_type_extra_spec(self, share_type_id, extra_spec_name):
uri = "types/%s/extra_specs/%s" % (share_type_id, extra_spec_name)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_type_extra_specs(self, share_type_id, params=None):
uri = "types/%s/extra_specs" % share_type_id
if params is not None:
uri += '?%s' % urlparse.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_type_extra_spec(self, share_type_id, spec_name,
spec_value):
uri = "types/%s/extra_specs/%s" % (share_type_id, spec_name)
extra_spec = {spec_name: spec_value}
post_body = json.dumps(extra_spec)
resp, body = self.put(uri, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_type_extra_specs(self, share_type_id, extra_specs):
uri = "types/%s/extra_specs" % share_type_id
extra_specs = {"extra_specs": extra_specs}
post_body = json.dumps(extra_specs)
resp, body = self.post(uri, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_type_extra_spec(self, share_type_id, extra_spec_name):
uri = "types/%s/extra_specs/%s" % (share_type_id, extra_spec_name)
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
###############
def list_share_servers(self, search_opts=None):
"""Get list of share servers."""
uri = "share-servers"
if search_opts:
uri += "?%s" % urlparse.urlencode(search_opts)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_server(self, share_server_id):
"""Delete share server by its ID."""
uri = "share-servers/%s" % share_server_id
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
def show_share_server(self, share_server_id):
"""Get share server info."""
uri = "share-servers/%s" % share_server_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def show_share_server_details(self, share_server_id):
"""Get share server details only."""
uri = "share-servers/%s/details" % share_server_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def list_pools(self, detail=False, search_opts=None):
"""Get list of scheduler pools."""
uri = 'scheduler-stats/pools'
if detail:
uri += '/detail'
if search_opts:
uri += "?%s" % urlparse.urlencode(search_opts)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return json.loads(body)
###############
def list_availability_zones(self):
"""Get list of availability zones."""
uri = 'os-availability-zone'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)

View File

@@ -1,18 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# 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.
from manila_tempest_tests.services.share.v2.json.shares_client import \
SharesV2Client
__all__ = ['SharesV2Client']

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +0,0 @@
# Copyright 2014 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.
from tempest.lib import exceptions
class ShareBuildErrorException(exceptions.TempestException):
message = "Share %(share_id)s failed to build and is in ERROR status"
class ShareInstanceBuildErrorException(exceptions.TempestException):
message = "Share instance %(id)s failed to build and is in ERROR status"
class ShareGroupBuildErrorException(exceptions.TempestException):
message = ("Share group %(share_group_id)s failed to build and "
"is in ERROR status")
class AccessRuleBuildErrorException(exceptions.TempestException):
message = "Share's rule with id %(rule_id)s is in ERROR status"
class SnapshotBuildErrorException(exceptions.TempestException):
message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
class SnapshotInstanceBuildErrorException(exceptions.TempestException):
message = ("Snapshot instance %(id)s failed to build and is in "
"ERROR status.")
class ShareGroupSnapshotBuildErrorException(exceptions.TempestException):
message = ("Share Group Snapshot %(share_group_snapshot_id)s failed "
"to build and is in ERROR status")
class ShareProtocolNotSpecified(exceptions.TempestException):
message = "Share can not be created, share protocol is not specified"
class ShareNetworkNotSpecified(exceptions.TempestException):
message = "Share can not be created, share network not specified"
class NoAvailableNetwork(exceptions.TempestException):
message = "No available network for service VM"
class InvalidResource(exceptions.TempestException):
message = "Provided invalid resource: %(message)s"
class ShareMigrationException(exceptions.TempestException):
message = ("Share %(share_id)s failed to migrate from "
"host %(src)s to host %(dest)s.")
class ResourceReleaseFailed(exceptions.TempestException):
message = "Failed to release resource '%(res_type)s' with id '%(res_id)s'."
class ShareReplicationTypeException(exceptions.TempestException):
message = ("Option backend_replication_type is set to incorrect value: "
"%(replication_type)s")

View File

@@ -1,128 +0,0 @@
# Copyright 2014 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.
from tempest import config
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class AdminActionsTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(AdminActionsTest, cls).resource_setup()
cls.states = ["error", "available"]
cls.task_states = ["migration_starting", "data_copying_in_progress",
"migration_success", None]
cls.bad_status = "error_deleting"
cls.sh = cls.create_share()
cls.sh_instance = (
cls.shares_v2_client.get_instances_of_share(cls.sh["id"])[0]
)
if CONF.share.run_snapshot_tests:
cls.sn = cls.create_snapshot_wait_for_active(cls.sh["id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_reset_share_state(self):
for status in self.states:
self.shares_v2_client.reset_state(self.sh["id"], status=status)
self.shares_v2_client.wait_for_share_status(self.sh["id"], status)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_reset_share_instance_state(self):
id = self.sh_instance["id"]
for status in self.states:
self.shares_v2_client.reset_state(
id, s_type="share_instances", status=status)
self.shares_v2_client.wait_for_share_instance_status(id, status)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_snapshot_state_to_error(self):
for status in self.states:
self.shares_v2_client.reset_state(
self.sn["id"], s_type="snapshots", status=status)
self.shares_v2_client.wait_for_snapshot_status(
self.sn["id"], status)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_force_delete_share(self):
share = self.create_share()
# Change status from 'available' to 'error_deleting'
self.shares_v2_client.reset_state(share["id"], status=self.bad_status)
# Check that status was changed
check_status = self.shares_v2_client.get_share(share["id"])
self.assertEqual(self.bad_status, check_status["status"])
# Share with status 'error_deleting' should be deleted
self.shares_v2_client.force_delete(share["id"])
self.shares_v2_client.wait_for_resource_deletion(share_id=share["id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_force_delete_share_instance(self):
share = self.create_share(cleanup_in_class=False)
instances = self.shares_v2_client.get_instances_of_share(share["id"])
# Check that instance was created
self.assertEqual(1, len(instances))
instance = instances[0]
# Change status from 'available' to 'error_deleting'
self.shares_v2_client.reset_state(
instance["id"], s_type="share_instances", status=self.bad_status)
# Check that status was changed
check_status = self.shares_v2_client.get_share_instance(instance["id"])
self.assertEqual(self.bad_status, check_status["status"])
# Share with status 'error_deleting' should be deleted
self.shares_v2_client.force_delete(
instance["id"], s_type="share_instances")
self.shares_v2_client.wait_for_resource_deletion(
share_instance_id=instance["id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_force_delete_snapshot(self):
sn = self.create_snapshot_wait_for_active(self.sh["id"])
# Change status from 'available' to 'error_deleting'
self.shares_v2_client.reset_state(
sn["id"], s_type="snapshots", status=self.bad_status)
# Check that status was changed
check_status = self.shares_v2_client.get_snapshot(sn["id"])
self.assertEqual(self.bad_status, check_status["status"])
# Snapshot with status 'error_deleting' should be deleted
self.shares_v2_client.force_delete(sn["id"], s_type="snapshots")
self.shares_v2_client.wait_for_resource_deletion(snapshot_id=sn["id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_reset_share_task_state(self):
for task_state in self.task_states:
self.shares_v2_client.reset_task_state(self.sh["id"], task_state)
self.shares_v2_client.wait_for_share_status(
self.sh["id"], task_state, 'task_state')

View File

@@ -1,210 +0,0 @@
# Copyright 2014 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.
import ddt
from tempest import config
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class AdminActionsNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(AdminActionsNegativeTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.sh = cls.create_share(client=cls.admin_client)
cls.sh_instance = (
cls.admin_client.get_instances_of_share(cls.sh["id"])[0]
)
if CONF.share.run_snapshot_tests:
cls.sn = cls.create_snapshot_wait_for_active(
cls.sh["id"], client=cls.admin_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_reset_share_state_to_unacceptable_state(self):
self.assertRaises(lib_exc.BadRequest,
self.admin_client.reset_state,
self.sh["id"], status="fake")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_reset_share_instance_state_to_unacceptable_state(self):
self.assertRaises(
lib_exc.BadRequest,
self.admin_client.reset_state,
self.sh_instance["id"],
s_type="share_instances",
status="fake"
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_snapshot_state_to_unacceptable_state(self):
self.assertRaises(lib_exc.BadRequest,
self.admin_client.reset_state,
self.sn["id"], s_type="snapshots", status="fake")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_reset_share_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.reset_state,
self.sh["id"])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_reset_share_instance_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.reset_state,
self.sh_instance["id"], s_type="share_instances")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_reset_snapshot_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.reset_state,
self.sn["id"], s_type="snapshots")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_force_delete_share_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.force_delete,
self.sh["id"])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_force_delete_share_instance_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.force_delete,
self.sh_instance["id"], s_type="share_instances")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_force_delete_snapshot_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.force_delete,
self.sn["id"], s_type="snapshots")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_get_share_instance_with_member(self):
# If a non-admin tries to get instance, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.get_share_instance,
self.sh_instance["id"])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_get_instances_of_share_with_member(self):
# If a non-admin tries to list instances of given share, it should be
# unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.get_instances_of_share,
self.sh['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_reset_task_state_invalid_state(self):
self.assertRaises(
lib_exc.BadRequest, self.admin_client.reset_task_state,
self.sh['id'], 'fake_state')
@ddt.ddt
class AdminActionsAPIOnlyNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(AdminActionsAPIOnlyNegativeTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_list_share_instance_with_member(self):
# If a non-admin tries to list instances, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_client.list_share_instances)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.22")
def test_reset_task_state_share_not_found(self):
self.assertRaises(
lib_exc.NotFound, self.admin_client.reset_task_state,
'fake_share', 'migration_error')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_force_delete_nonexistent_snapshot(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.force_delete,
"fake",
s_type="snapshots")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_force_delete_nonexistent_share(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.force_delete, "fake")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_force_delete_nonexistent_share_instance(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.force_delete,
"fake",
s_type="share_instances")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_reset_nonexistent_share_state(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.reset_state, "fake")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_reset_nonexistent_share_instance_state(self):
self.assertRaises(lib_exc.NotFound, self.admin_client.reset_state,
"fake", s_type="share_instances")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_nonexistent_snapshot_state(self):
self.assertRaises(lib_exc.NotFound, self.admin_client.reset_state,
"fake", s_type="snapshots")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@ddt.data('migrate_share', 'migration_complete', 'reset_task_state',
'migration_get_progress', 'migration_cancel')
def test_migration_API_invalid_microversion(self, method_name):
if method_name == 'migrate_share':
self.assertRaises(
lib_exc.NotFound, getattr(self.shares_v2_client, method_name),
'fake_share', 'fake_host', version='2.21')
elif method_name == 'reset_task_state':
self.assertRaises(
lib_exc.NotFound, getattr(self.shares_v2_client, method_name),
'fake_share', 'fake_task_state', version='2.21')
else:
self.assertRaises(
lib_exc.NotFound, getattr(self.shares_v2_client, method_name),
'fake_share', version='2.21')

View File

@@ -1,201 +0,0 @@
# Copyright 2015 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.
import ddt
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
from tempest import config
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
LATEST_MICROVERSION = CONF.share.max_api_microversion
@base.skip_if_microversion_not_supported("2.9")
@ddt.ddt
class ExportLocationsTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ExportLocationsTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.share = cls.create_share(client=cls.admin_client)
cls.share = cls.admin_client.get_share(cls.share['id'])
cls.share_instances = cls.admin_client.get_instances_of_share(
cls.share['id'])
def _verify_export_location_structure(
self, export_locations, role='admin', version=LATEST_MICROVERSION,
format='summary'):
# Determine which keys to expect based on role, version and format
summary_keys = ['id', 'path']
if utils.is_microversion_ge(version, '2.14'):
summary_keys += ['preferred']
admin_summary_keys = summary_keys + [
'share_instance_id', 'is_admin_only']
detail_keys = summary_keys + ['created_at', 'updated_at']
admin_detail_keys = admin_summary_keys + ['created_at', 'updated_at']
if format == 'summary':
if role == 'admin':
expected_keys = admin_summary_keys
else:
expected_keys = summary_keys
else:
if role == 'admin':
expected_keys = admin_detail_keys
else:
expected_keys = detail_keys
if not isinstance(export_locations, (list, tuple, set)):
export_locations = (export_locations, )
for export_location in export_locations:
# Check that the correct keys are present
self.assertEqual(len(expected_keys), len(export_location))
for key in expected_keys:
self.assertIn(key, export_location)
# Check the format of ever-present summary keys
self.assertTrue(uuidutils.is_uuid_like(export_location['id']))
self.assertIsInstance(export_location['path'],
six.string_types)
if utils.is_microversion_ge(version, '2.14'):
self.assertIn(export_location['preferred'], (True, False))
if role == 'admin':
self.assertIn(export_location['is_admin_only'], (True, False))
self.assertTrue(uuidutils.is_uuid_like(
export_location['share_instance_id']))
# Check the format of the detail keys
if format == 'detail':
for time in (export_location['created_at'],
export_location['updated_at']):
# If var 'time' has incorrect value then ValueError
# exception is expected to be raised. So, just try parse
# it making assertion that it has proper date value.
timeutils.parse_strtime(time)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@utils.skip_if_microversion_not_supported('2.13')
def test_list_share_export_locations(self):
export_locations = self.admin_client.list_share_export_locations(
self.share['id'], version='2.13')
self._verify_export_location_structure(export_locations,
version='2.13')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@utils.skip_if_microversion_not_supported('2.14')
def test_list_share_export_locations_with_preferred_flag(self):
export_locations = self.admin_client.list_share_export_locations(
self.share['id'], version='2.14')
self._verify_export_location_structure(export_locations,
version='2.14')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_get_share_export_location(self):
export_locations = self.admin_client.list_share_export_locations(
self.share['id'])
for export_location in export_locations:
el = self.admin_client.get_share_export_location(
self.share['id'], export_location['id'])
self._verify_export_location_structure(el, format='detail')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_export_locations_by_member(self):
export_locations = self.member_client.list_share_export_locations(
self.share['id'])
self._verify_export_location_structure(export_locations, role='member')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_get_share_export_location_by_member(self):
export_locations = self.admin_client.list_share_export_locations(
self.share['id'])
for export_location in export_locations:
if export_location['is_admin_only']:
continue
el = self.member_client.get_share_export_location(
self.share['id'], export_location['id'])
self._verify_export_location_structure(el, role='member',
format='detail')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@utils.skip_if_microversion_not_supported('2.13')
def test_list_share_instance_export_locations(self):
for share_instance in self.share_instances:
export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance['id'], version='2.13'))
self._verify_export_location_structure(export_locations,
version='2.13')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@utils.skip_if_microversion_not_supported('2.14')
def test_list_share_instance_export_locations_with_preferred_flag(self):
for share_instance in self.share_instances:
export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance['id'], version='2.14'))
self._verify_export_location_structure(export_locations,
version='2.14')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_get_share_instance_export_location(self):
for share_instance in self.share_instances:
export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance['id']))
for el in export_locations:
el = self.admin_client.get_share_instance_export_location(
share_instance['id'], el['id'])
self._verify_export_location_structure(el, format='detail')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_share_contains_all_export_locations_of_all_share_instances(self):
share_export_locations = self.admin_client.list_share_export_locations(
self.share['id'])
share_instances_export_locations = []
for share_instance in self.share_instances:
share_instance_export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance['id']))
share_instances_export_locations.extend(
share_instance_export_locations)
self.assertEqual(
len(share_export_locations),
len(share_instances_export_locations)
)
self.assertEqual(
sorted(share_export_locations, key=lambda el: el['id']),
sorted(share_instances_export_locations, key=lambda el: el['id'])
)

View File

@@ -1,97 +0,0 @@
# Copyright 2015 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.
from tempest import config
from tempest.lib import exceptions as lib_exc
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@base.skip_if_microversion_not_supported("2.9")
class ExportLocationsNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ExportLocationsNegativeTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.share = cls.create_share(client=cls.admin_client)
cls.share = cls.admin_client.get_share(cls.share['id'])
cls.share_instances = cls.admin_client.get_instances_of_share(
cls.share['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_get_inexistent_share_export_location(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_client.get_share_export_location,
self.share['id'],
"fake-inexistent-share-instance-id",
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_get_inexistent_share_instance_export_location(self):
for share_instance in self.share_instances:
self.assertRaises(
lib_exc.NotFound,
self.admin_client.get_share_instance_export_location,
share_instance['id'],
"fake-inexistent-share-instance-id",
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_instance_export_locations_by_member(self):
for share_instance in self.share_instances:
self.assertRaises(
lib_exc.Forbidden,
self.member_client.list_share_instance_export_locations,
"fake-inexistent-share-instance-id",
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_get_share_instance_export_location_by_member(self):
for share_instance in self.share_instances:
export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance['id']))
for el in export_locations:
self.assertRaises(
lib_exc.Forbidden,
self.member_client.get_share_instance_export_location,
share_instance['id'], el['id'],
)
@base.skip_if_microversion_not_supported("2.9")
class ExportLocationsAPIOnlyNegativeTest(base.BaseSharesAdminTest):
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_export_locations_by_nonexistent_share(self):
self.assertRaises(
lib_exc.NotFound,
self.shares_v2_client.list_share_export_locations,
"fake-inexistent-share-id",
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_export_locations_by_nonexistent_share_instance(self):
self.assertRaises(
lib_exc.NotFound,
self.shares_v2_client.list_share_instance_export_locations,
"fake-inexistent-share-instance-id",
)

View File

@@ -1,634 +0,0 @@
# Copyright 2015 Hitachi Data Systems.
# 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
class MigrationBase(base.BaseSharesAdminTest):
"""Base test class for Share Migration.
Tests share migration in multi-backend environment.
This class covers:
1) Driver-assisted migration: force_host_assisted_migration, nondisruptive,
writable and preserve-metadata are False.
2) Host-assisted migration: force_host_assisted_migration is True,
nondisruptive, writable, preserve-metadata and preserve-snapshots are
False.
3) 2-phase migration of both Host-assisted and Driver-assisted.
4) Cancelling migration past first phase.
5) Changing driver modes through migration.
No need to test with writable, preserve-metadata and non-disruptive as
True, values are supplied to the driver which decides what to do. Test
should be positive, so not being writable, not preserving metadata and
being disruptive is less restrictive for drivers, which would abort if they
cannot handle them.
Drivers that implement driver-assisted migration should enable the
configuration flag to be tested.
"""
protocol = None
@classmethod
def resource_setup(cls):
super(MigrationBase, cls).resource_setup()
if cls.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled." % cls.protocol
raise cls.skipException(message)
if not (CONF.share.run_host_assisted_migration_tests or
CONF.share.run_driver_assisted_migration_tests):
raise cls.skipException("Share migration tests are disabled.")
cls.pools = cls.shares_v2_client.list_pools(detail=True)['pools']
if len(cls.pools) < 2:
raise cls.skipException("At least two different pool entries are "
"needed to run share migration tests.")
cls.new_type = cls.create_share_type(
name=data_utils.rand_name('new_share_type_for_migration'),
cleanup_in_class=True,
extra_specs=utils.get_configured_extra_specs())
cls.new_type_opposite = cls.create_share_type(
name=data_utils.rand_name('new_share_type_for_migration_opposite'),
cleanup_in_class=True,
extra_specs=utils.get_configured_extra_specs(
variation='opposite_driver_modes'))
def _setup_migration(self, share, opposite=False):
if opposite:
dest_type = self.new_type_opposite['share_type']
else:
dest_type = self.new_type['share_type']
dest_pool = utils.choose_matching_backend(share, self.pools, dest_type)
if opposite:
if not dest_pool:
raise self.skipException(
"This test requires two pools enabled with different "
"driver modes.")
else:
self.assertIsNotNone(dest_pool)
self.assertIsNotNone(dest_pool.get('name'))
old_exports = self.shares_v2_client.list_share_export_locations(
share['id'])
self.assertNotEmpty(old_exports)
old_exports = [x['path'] for x in old_exports
if x['is_admin_only'] is False]
self.assertNotEmpty(old_exports)
self.shares_v2_client.create_access_rule(
share['id'], access_to="50.50.50.50", access_level="rw")
self.shares_v2_client.wait_for_share_status(
share['id'], constants.RULE_STATE_ACTIVE,
status_attr='access_rules_status')
self.shares_v2_client.create_access_rule(
share['id'], access_to="51.51.51.51", access_level="ro")
self.shares_v2_client.wait_for_share_status(
share['id'], constants.RULE_STATE_ACTIVE,
status_attr='access_rules_status')
dest_pool = dest_pool['name']
share = self.shares_v2_client.get_share(share['id'])
return share, dest_pool
def _validate_migration_successful(self, dest_pool, share, status_to_wait,
version=CONF.share.max_api_microversion,
complete=True, share_network_id=None,
share_type_id=None):
statuses = ((status_to_wait,)
if not isinstance(status_to_wait, (tuple, list, set))
else status_to_wait)
new_exports = self.shares_v2_client.list_share_export_locations(
share['id'], version=version)
self.assertNotEmpty(new_exports)
new_exports = [x['path'] for x in new_exports if
x['is_admin_only'] is False]
self.assertNotEmpty(new_exports)
self.assertIn(share['task_state'], statuses)
if share_network_id:
self.assertEqual(share_network_id, share['share_network_id'])
if share_type_id:
self.assertEqual(share_type_id, share['share_type'])
# Share migrated
if complete:
self.assertEqual(dest_pool, share['host'])
rules = self.shares_v2_client.list_access_rules(share['id'])
expected_rules = [{
'state': constants.RULE_STATE_ACTIVE,
'access_to': '50.50.50.50',
'access_type': 'ip',
'access_level': 'rw',
}, {
'state': constants.RULE_STATE_ACTIVE,
'access_to': '51.51.51.51',
'access_type': 'ip',
'access_level': 'ro',
}]
filtered_rules = [{'state': rule['state'],
'access_to': rule['access_to'],
'access_level': rule['access_level'],
'access_type': rule['access_type']}
for rule in rules]
for r in expected_rules:
self.assertIn(r, filtered_rules)
self.assertEqual(len(expected_rules), len(filtered_rules))
# Share not migrated yet
else:
self.assertNotEqual(dest_pool, share['host'])
def _check_migration_enabled(self, force_host_assisted):
if force_host_assisted:
if not CONF.share.run_host_assisted_migration_tests:
raise self.skipException(
"Host-assisted migration tests are disabled.")
else:
if not CONF.share.run_driver_assisted_migration_tests:
raise self.skipException(
"Driver-assisted migration tests are disabled.")
def _create_secondary_share_network(self, old_share_network_id):
old_share_network = self.shares_v2_client.get_share_network(
old_share_network_id)
new_share_network = self.create_share_network(
cleanup_in_class=True,
neutron_net_id=old_share_network['neutron_net_id'],
neutron_subnet_id=old_share_network['neutron_subnet_id'])
return new_share_network['id']
def _test_resize_post_migration(self, force_host_assisted, resize):
self._check_migration_enabled(force_host_assisted)
new_size = CONF.share.share_size + 1
share = self.create_share(self.protocol, size=new_size)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share)
task_state, new_share_network_id, new_share_type_id = (
self._get_migration_data(share, force_host_assisted))
share = self.migrate_share(
share['id'], dest_pool,
force_host_assisted_migration=force_host_assisted,
wait_for_status=task_state, new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id)
share = self.migration_complete(share['id'], dest_pool)
if resize == 'extend':
new_size = CONF.share.share_size + 2
self.shares_v2_client.extend_share(share['id'], new_size)
self.shares_v2_client.wait_for_share_status(
share['id'], constants.STATUS_AVAILABLE)
share = self.shares_v2_client.get_share(share["id"])
self.assertEqual(new_size, int(share["size"]))
else:
new_size = CONF.share.share_size
self.shares_v2_client.shrink_share(share['id'], new_size)
self.shares_v2_client.wait_for_share_status(
share['id'], constants.STATUS_AVAILABLE)
share = self.shares_v2_client.get_share(share["id"])
self.assertEqual(new_size, int(share["size"]))
self._cleanup_share(share)
def _get_migration_data(self, share, force_host_assisted=False):
task_state = (constants.TASK_STATE_DATA_COPYING_COMPLETED
if force_host_assisted
else constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
old_share_network_id = share['share_network_id']
if CONF.share.multitenancy_enabled:
new_share_network_id = self._create_secondary_share_network(
old_share_network_id)
else:
new_share_network_id = None
new_share_type_id = self.new_type['share_type']['id']
return task_state, new_share_network_id, new_share_type_id
def _validate_snapshot(self, share, snapshot1, snapshot2):
snapshot_list = self.shares_v2_client.list_snapshots_for_share(
share['id'])
msg = "Share %s has no snapshot." % share['id']
# Verify that snapshot list is not empty
self.assertNotEmpty(snapshot_list, msg)
snapshot_id_list = [snap['id'] for snap in snapshot_list]
# verify that after migration original snapshots are retained
self.assertIn(snapshot1['id'], snapshot_id_list)
self.assertIn(snapshot2['id'], snapshot_id_list)
# Verify that a share can be created from a snapshot after migration
snapshot1_share = self.create_share(
self.protocol, size=share['size'], snapshot_id=snapshot1['id'],
share_network_id=share['share_network_id'])
self.assertEqual(snapshot1['id'], snapshot1_share['snapshot_id'])
self._cleanup_share(share)
def _validate_share_migration_with_different_snapshot_capability_type(
self, force_host_assisted, snapshot_capable):
self._check_migration_enabled(force_host_assisted)
ss_type, no_ss_type = self._create_share_type_for_snapshot_capability()
if snapshot_capable:
share_type = ss_type['share_type']
share_type_id = no_ss_type['share_type']['id']
new_share_type_id = ss_type['share_type']['id']
else:
share_type = no_ss_type['share_type']
share_type_id = ss_type['share_type']['id']
new_share_type_id = no_ss_type['share_type']['id']
share = self.create_share(
self.protocol, share_type_id=share_type_id)
share = self.shares_v2_client.get_share(share['id'])
if snapshot_capable:
self.assertEqual(False, share['snapshot_support'])
else:
# Verify that share has snapshot support capability
self.assertTrue(share['snapshot_support'])
dest_pool = utils.choose_matching_backend(share, self.pools,
share_type)
task_state, new_share_network_id, __ = (
self._get_migration_data(share, force_host_assisted))
share = self.migrate_share(
share['id'], dest_pool['name'],
force_host_assisted_migration=force_host_assisted,
wait_for_status=task_state,
new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id)
share = self.migration_complete(share['id'], dest_pool)
if snapshot_capable:
# Verify that migrated share does have snapshot support capability
self.assertTrue(share['snapshot_support'])
else:
# Verify that migrated share don't have snapshot support capability
self.assertEqual(False, share['snapshot_support'])
self._cleanup_share(share)
def _create_share_type_for_snapshot_capability(self):
# Share type with snapshot support
st_name = data_utils.rand_name(
'snapshot_capable_share_type_for_migration')
extra_specs = self.add_extra_specs_to_dict({"snapshot_support": True})
ss_type = self.create_share_type(st_name, extra_specs=extra_specs)
# New share type with no snapshot support capability
# to which a share will be migrated
new_st_name = data_utils.rand_name(
'snapshot_noncapable_share_type_for_migration')
extra_specs = {
"driver_handles_share_servers": CONF.share.multitenancy_enabled
}
no_ss_type = self.create_share_type(new_st_name,
extra_specs=extra_specs)
return ss_type, no_ss_type
def _cleanup_share(self, share):
resource = {"type": "share", "id": share["id"],
"client": self.shares_v2_client}
# NOTE(Yogi1): Share needs to be cleaned up explicitly at the end of
# test otherwise, newly created share_network will not get cleaned up.
self.method_resources.insert(0, resource)
@ddt.ddt
class MigrationCancelNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data(True, False)
def test_migration_cancel(self, force_host_assisted):
self._check_migration_enabled(force_host_assisted)
share = self.create_share(self.protocol)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share)
task_state = (constants.TASK_STATE_DATA_COPYING_COMPLETED
if force_host_assisted
else constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
share = self.migrate_share(
share['id'], dest_pool, wait_for_status=task_state,
force_host_assisted_migration=force_host_assisted)
self._validate_migration_successful(
dest_pool, share, task_state, complete=False)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(task_state, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
share = self.migration_cancel(share['id'], dest_pool)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(
constants.TASK_STATE_MIGRATION_CANCELLED, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
self._validate_migration_successful(
dest_pool, share, constants.TASK_STATE_MIGRATION_CANCELLED,
complete=False)
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(
CONF.share.run_snapshot_tests, 'Snapshot tests are disabled.')
@testtools.skipUnless(
CONF.share.run_driver_assisted_migration_tests,
'Driver-assisted migration tests are disabled.')
@testtools.skipUnless(
CONF.share.run_migration_with_preserve_snapshots_tests,
'Migration with preserve snapshots tests are disabled.')
def test_migration_cancel_share_with_snapshot(self):
share = self.create_share(self.protocol)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share)
snapshot1 = self.create_snapshot_wait_for_active(share['id'])
snapshot2 = self.create_snapshot_wait_for_active(share['id'])
task_state, new_share_network_id, new_share_type_id = (
self._get_migration_data(share))
share = self.migrate_share(
share['id'], dest_pool,
wait_for_status=task_state, new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id, preserve_snapshots=True)
share = self.migration_cancel(share['id'], dest_pool)
self._validate_snapshot(share, snapshot1, snapshot2)
@ddt.ddt
class MigrationOppositeDriverModesNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data(True, False)
def test_migration_opposite_driver_modes(self, force_host_assisted):
self._check_migration_enabled(force_host_assisted)
share = self.create_share(self.protocol)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share, opposite=True)
if not CONF.share.multitenancy_enabled:
# If currently configured is DHSS=False,
# then we need it for DHSS=True
new_share_network_id = self.provide_share_network(
self.shares_v2_client,
self.networks_client,
isolated_creds_client=None,
ignore_multitenancy_config=True,
)
else:
# If currently configured is DHSS=True,
# then we must pass None for DHSS=False
new_share_network_id = None
old_share_network_id = share['share_network_id']
old_share_type_id = share['share_type']
new_share_type_id = self.new_type_opposite['share_type']['id']
task_state = (constants.TASK_STATE_DATA_COPYING_COMPLETED
if force_host_assisted
else constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
share = self.migrate_share(
share['id'], dest_pool,
force_host_assisted_migration=force_host_assisted,
wait_for_status=task_state, new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id)
self._validate_migration_successful(
dest_pool, share, task_state, complete=False,
share_network_id=old_share_network_id,
share_type_id=old_share_type_id)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(task_state, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
share = self.migration_complete(share['id'], dest_pool)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(
constants.TASK_STATE_MIGRATION_SUCCESS, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
self._validate_migration_successful(
dest_pool, share, constants.TASK_STATE_MIGRATION_SUCCESS,
complete=True, share_network_id=new_share_network_id,
share_type_id=new_share_type_id)
@ddt.ddt
class MigrationTwoPhaseNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data(True, False)
def test_migration_2phase(self, force_host_assisted):
self._check_migration_enabled(force_host_assisted)
share = self.create_share(self.protocol)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share)
old_share_network_id = share['share_network_id']
old_share_type_id = share['share_type']
task_state, new_share_network_id, new_share_type_id = (
self._get_migration_data(share, force_host_assisted))
share = self.migrate_share(
share['id'], dest_pool,
force_host_assisted_migration=force_host_assisted,
wait_for_status=task_state, new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id)
self._validate_migration_successful(
dest_pool, share, task_state, complete=False,
share_network_id=old_share_network_id,
share_type_id=old_share_type_id)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(task_state, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
share = self.migration_complete(share['id'], dest_pool)
progress = self.shares_v2_client.migration_get_progress(share['id'])
self.assertEqual(
constants.TASK_STATE_MIGRATION_SUCCESS, progress['task_state'])
self.assertEqual(100, progress['total_progress'])
self._validate_migration_successful(
dest_pool, share, constants.TASK_STATE_MIGRATION_SUCCESS,
complete=True, share_network_id=new_share_network_id,
share_type_id=new_share_type_id)
self._cleanup_share(share)
@ddt.ddt
class MigrationWithShareExtendingNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(
CONF.share.run_extend_tests, 'Extend share tests are disabled.')
@ddt.data(True, False)
def test_extend_on_migrated_share(self, force_host_assisted):
self._test_resize_post_migration(force_host_assisted, resize='extend')
@ddt.ddt
class MigrationWithShareShrinkingNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(
CONF.share.run_shrink_tests, 'Shrink share tests are disabled.')
@ddt.data(True, False)
def test_shrink_on_migrated_share(self, force_host_assisted):
self._test_resize_post_migration(force_host_assisted, resize='shrink')
@ddt.ddt
class MigrationOfShareWithSnapshotNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(
CONF.share.run_snapshot_tests, 'Snapshot tests are disabled.')
@testtools.skipUnless(
CONF.share.run_driver_assisted_migration_tests,
'Driver-assisted migration tests are disabled.')
@testtools.skipUnless(
CONF.share.run_migration_with_preserve_snapshots_tests,
'Migration with preserve snapshots tests are disabled.')
def test_migrating_share_with_snapshot(self):
ss_type, __ = self._create_share_type_for_snapshot_capability()
share = self.create_share(self.protocol, cleanup_in_class=False)
share = self.shares_v2_client.get_share(share['id'])
share, dest_pool = self._setup_migration(share)
snapshot1 = self.create_snapshot_wait_for_active(
share['id'], cleanup_in_class=False)
snapshot2 = self.create_snapshot_wait_for_active(
share['id'], cleanup_in_class=False)
task_state, new_share_network_id, __ = self._get_migration_data(share)
share = self.migrate_share(
share['id'], dest_pool,
wait_for_status=task_state,
new_share_type_id=ss_type['share_type']['id'],
new_share_network_id=new_share_network_id, preserve_snapshots=True)
share = self.migration_complete(share['id'], dest_pool)
self._validate_snapshot(share, snapshot1, snapshot2)
@ddt.ddt
class MigrationWithDifferentSnapshotSupportNFSTest(MigrationBase):
protocol = "nfs"
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(CONF.share.run_snapshot_tests,
'Snapshot tests are disabled.')
@ddt.data(True, False)
def test_migrate_share_to_snapshot_capability_share_type(
self, force_host_assisted):
# Verify that share with no snapshot support type can be migrated
# to new share type which supports the snapshot
self._validate_share_migration_with_different_snapshot_capability_type(
force_host_assisted, True)
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(CONF.share.run_snapshot_tests,
'Snapshot tests are disabled.')
@ddt.data(True, False)
def test_migrate_share_to_no_snapshot_capability_share_type(
self, force_host_assisted):
# Verify that share with snapshot support type can be migrated
# to new share type which doesn't support the snapshot
self._validate_share_migration_with_different_snapshot_capability_type(
force_host_assisted, False)
# NOTE(u_glide): this function is required to exclude MigrationBase from
# executed test cases.
# See: https://docs.python.org/2/library/unittest.html#load-tests-protocol
# for details.
def load_tests(loader, tests, _):
result = []
for test_case in tests:
if not test_case._tests or type(test_case._tests[0]) is MigrationBase:
continue
result.append(test_case)
return loader.suiteClass(result)

View File

@@ -1,326 +0,0 @@
# Copyright 2015 Hitachi Data Systems.
# 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
@ddt.ddt
class MigrationNegativeTest(base.BaseSharesAdminTest):
"""Tests Share Migration.
Tests share migration in multi-backend environment.
"""
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(MigrationNegativeTest, cls).resource_setup()
if cls.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled." % cls.protocol
raise cls.skipException(message)
if not (CONF.share.run_host_assisted_migration_tests or
CONF.share.run_driver_assisted_migration_tests):
raise cls.skipException("Share migration tests are disabled.")
pools = cls.shares_client.list_pools(detail=True)['pools']
if len(pools) < 2:
raise cls.skipException("At least two different pool entries "
"are needed to run share migration tests.")
cls.share = cls.create_share(cls.protocol,
size=CONF.share.share_size+1)
cls.share = cls.shares_client.get_share(cls.share['id'])
cls.default_type = cls.shares_v2_client.list_share_types(
default=True)['share_type']
dest_pool = utils.choose_matching_backend(
cls.share, pools, cls.default_type)
if not dest_pool or dest_pool.get('name') is None:
raise share_exceptions.ShareMigrationException(
"No valid pool entries to run share migration tests.")
cls.dest_pool = dest_pool['name']
cls.new_type_invalid = cls.create_share_type(
name=data_utils.rand_name(
'new_invalid_share_type_for_migration'),
cleanup_in_class=True,
extra_specs=utils.get_configured_extra_specs(variation='invalid'))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_cancel_invalid(self):
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migration_cancel,
self.share['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_get_progress_None(self):
self.shares_v2_client.reset_task_state(self.share["id"], None)
self.shares_v2_client.wait_for_share_status(
self.share["id"], None, 'task_state')
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migration_get_progress,
self.share['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_complete_invalid(self):
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migration_complete,
self.share['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_cancel_not_found(self):
self.assertRaises(
lib_exc.NotFound, self.shares_v2_client.migration_cancel,
'invalid_share_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_get_progress_not_found(self):
self.assertRaises(
lib_exc.NotFound, self.shares_v2_client.migration_get_progress,
'invalid_share_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.22")
def test_migration_complete_not_found(self):
self.assertRaises(
lib_exc.NotFound, self.shares_v2_client.migration_complete,
'invalid_share_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_migrate_share_with_snapshot(self):
snap = self.create_snapshot_wait_for_active(self.share['id'])
self.assertRaises(
lib_exc.Conflict, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool,
force_host_assisted_migration=True)
self.shares_v2_client.delete_snapshot(snap['id'])
self.shares_v2_client.wait_for_resource_deletion(snapshot_id=snap[
"id"])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data(True, False)
def test_migrate_share_same_host(self, specified):
new_share_type_id = None
new_share_network_id = None
if specified:
new_share_type_id = self.default_type['id']
new_share_network_id = self.share['share_network_id']
self.migrate_share(
self.share['id'], self.share['host'],
wait_for_status=constants.TASK_STATE_MIGRATION_SUCCESS,
new_share_type_id=new_share_type_id,
new_share_network_id=new_share_network_id)
# NOTE(ganso): No need to assert, it is already waiting for correct
# status (migration_success).
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_host_invalid(self):
self.assertRaises(
lib_exc.NotFound, self.shares_v2_client.migrate_share,
self.share['id'], 'invalid_host')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data({'writable': False, 'preserve_metadata': False,
'preserve_snapshots': False, 'nondisruptive': True},
{'writable': False, 'preserve_metadata': False,
'preserve_snapshots': True, 'nondisruptive': False},
{'writable': False, 'preserve_metadata': True,
'preserve_snapshots': False, 'nondisruptive': False},
{'writable': True, 'preserve_metadata': False,
'preserve_snapshots': False, 'nondisruptive': False})
@ddt.unpack
def test_migrate_share_host_assisted_not_allowed_API(
self, writable, preserve_metadata, preserve_snapshots,
nondisruptive):
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool,
force_host_assisted_migration=True, writable=writable,
preserve_metadata=preserve_metadata, nondisruptive=nondisruptive,
preserve_snapshots=preserve_snapshots)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_change_type_no_valid_host(self):
if not CONF.share.multitenancy_enabled:
new_share_network_id = self.create_share_network(
neutron_net_id='fake_net_id',
neutron_subnet_id='fake_subnet_id')['id']
else:
new_share_network_id = None
self.shares_v2_client.migrate_share(
self.share['id'], self.dest_pool,
new_share_type_id=self.new_type_invalid['share_type']['id'],
new_share_network_id=new_share_network_id)
self.shares_v2_client.wait_for_migration_status(
self.share['id'], self.dest_pool,
constants.TASK_STATE_MIGRATION_ERROR)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_not_found(self):
self.assertRaises(
lib_exc.NotFound, self.shares_v2_client.migrate_share,
'invalid_share_id', self.dest_pool)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_not_available(self):
self.shares_client.reset_state(self.share['id'],
constants.STATUS_ERROR)
self.shares_client.wait_for_share_status(self.share['id'],
constants.STATUS_ERROR)
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool)
self.shares_client.reset_state(self.share['id'],
constants.STATUS_AVAILABLE)
self.shares_client.wait_for_share_status(self.share['id'],
constants.STATUS_AVAILABLE)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_invalid_share_network(self):
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool,
new_share_network_id='invalid_net_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_invalid_share_type(self):
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool,
new_share_type_id='invalid_type_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_migrate_share_opposite_type_share_network_invalid(self):
extra_specs = utils.get_configured_extra_specs(
variation='opposite_driver_modes')
new_type_opposite = self.create_share_type(
name=data_utils.rand_name('share_type_migration_negative'),
extra_specs=extra_specs)
new_share_network_id = None
if CONF.share.multitenancy_enabled:
new_share_network_id = self.create_share_network(
neutron_net_id='fake_net_id',
neutron_subnet_id='fake_subnet_id')['id']
self.assertRaises(
lib_exc.BadRequest, self.shares_v2_client.migrate_share,
self.share['id'], self.dest_pool,
new_share_type_id=new_type_opposite['share_type']['id'],
new_share_network_id=new_share_network_id)
@testtools.skipUnless(CONF.share.run_driver_assisted_migration_tests,
"Driver-assisted migration tests are disabled.")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_create_snapshot_during_share_migration(self):
self._test_share_actions_during_share_migration('create_snapshot', [])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
@ddt.data(('extend_share', [CONF.share.share_size + 2]),
('shrink_share', [CONF.share.share_size]))
@ddt.unpack
def test_share_resize_during_share_migration(self, method_name, *args):
self._test_share_actions_during_share_migration(method_name, *args)
def skip_if_tests_are_disabled(self, method_name):
property_to_evaluate = {
'extend_share': CONF.share.run_extend_tests,
'shrink_share': CONF.share.run_shrink_tests,
'create_snapshot': CONF.share.run_snapshot_tests,
}
if not property_to_evaluate[method_name]:
raise self.skipException(method_name + 'tests are disabled.')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.29")
def test_add_access_rule_during_migration(self):
access_type = "ip"
access_to = "50.50.50.50"
self.shares_v2_client.reset_state(self.share['id'],
constants.STATUS_MIGRATING)
self.shares_v2_client.reset_task_state(
self.share['id'],
constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
self.assertRaises(
lib_exc.BadRequest,
self.shares_v2_client.create_access_rule,
self.share['id'], access_type, access_to)
# Revert the migration state by cancelling the migration
self.shares_v2_client.reset_state(self.share['id'],
constants.STATUS_AVAILABLE)
self.shares_v2_client.reset_task_state(
self.share['id'],
constants.TASK_STATE_MIGRATION_CANCELLED)
def _test_share_actions_during_share_migration(self, method_name, *args):
self.skip_if_tests_are_disabled(method_name)
# Verify various share operations during share migration
self.shares_v2_client.reset_state(self.share['id'],
constants.STATUS_MIGRATING)
self.shares_v2_client.reset_task_state(
self.share['id'],
constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
self.assertRaises(
lib_exc.BadRequest, getattr(self.shares_v2_client, method_name),
self.share['id'], *args)
# Revert the migration state by cancelling the migration
self.shares_v2_client.reset_state(self.share['id'],
constants.STATUS_AVAILABLE)
self.shares_v2_client.reset_task_state(
self.share['id'],
constants.TASK_STATE_MIGRATION_CANCELLED)

View File

@@ -1,91 +0,0 @@
# Copyright 2014 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.
from tempest import config
from tempest.lib.common.utils import data_utils
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareMultiBackendTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareMultiBackendTest, cls).resource_setup()
if not CONF.share.multi_backend:
raise cls.skipException("Manila multi-backend tests are disabled.")
elif len(CONF.share.backend_names) < 2:
raise cls.skipException("For running multi-backend tests required"
" two names in config. Skipping.")
elif any(not name for name in CONF.share.backend_names):
raise cls.skipException("Share backend names can not be empty. "
"Skipping.")
cls.sts = []
cls.shares = []
share_data_list = []
# Create share types
for i in [0, 1]:
st_name = data_utils.rand_name("share-type-%s" % str(i))
extra_specs = {
"share_backend_name": CONF.share.backend_names[i],
}
st = cls.create_share_type(
name=st_name,
extra_specs=cls.add_extra_specs_to_dict(extra_specs))
cls.sts.append(st["share_type"])
st_id = st["share_type"]["id"]
share_data_list.append({"kwargs": {"share_type_id": st_id}})
# Create shares using precreated share types
cls.shares = cls.create_shares(share_data_list)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_share_backend_name_reporting(self):
# Share's 'host' should be like "hostname@backend_name"
for share in self.shares:
get = self.shares_client.get_share(share['id'])
self.assertEqual(2, len(get["host"].split("@")))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_share_share_type(self):
# Share type should be the same as provided with share creation
for i in [0, 1]:
get = self.shares_v2_client.get_share(self.shares[i]['id'],
version="2.5")
self.assertEqual(self.sts[i]["name"], get["share_type"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_share_share_type_v_2_6(self):
# Share type should be the same as provided with share creation
for i in [0, 1]:
get = self.shares_v2_client.get_share(self.shares[i]['id'],
version="2.6")
self.assertEqual(self.sts[i]["id"], get["share_type"])
self.assertEqual(self.sts[i]["name"], get["share_type_name"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_share_backend_name_distinction(self):
# Different share backends should have different host records
if CONF.share.backend_names[0] == CONF.share.backend_names[1]:
raise self.skipException("Share backends "
"configured with same name. Skipping.")
get1 = self.shares_client.get_share(self.shares[0]['id'])
get2 = self.shares_client.get_share(self.shares[1]['id'])
self.assertNotEqual(get1["host"], get2["host"])

View File

@@ -1,759 +0,0 @@
# Copyright 2014 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
PRE_SHARE_GROUPS_MICROVERSION = "2.39"
SHARE_GROUPS_MICROVERSION = "2.40"
@ddt.ddt
class SharesAdminQuotasTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
if not CONF.share.run_quota_tests:
msg = "Quota tests are disabled."
raise cls.skipException(msg)
super(SharesAdminQuotasTest, cls).resource_setup()
cls.user_id = cls.shares_v2_client.user_id
cls.tenant_id = cls.shares_v2_client.tenant_id
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_default_quotas(self):
quotas = self.shares_v2_client.default_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
self.assertGreater(int(quotas["share_groups"]), -2)
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_show_quotas(self):
quotas = self.shares_v2_client.show_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
self.assertGreater(int(quotas["share_groups"]), -2)
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_show_quotas_for_user(self):
quotas = self.shares_v2_client.show_quotas(
self.tenant_id, self.user_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
self.assertGreater(int(quotas["share_groups"]), -2)
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
def test_show_sg_quotas_using_too_old_microversion(self):
quotas = self.shares_v2_client.show_quotas(
self.tenant_id, version=PRE_SHARE_GROUPS_MICROVERSION)
for key in ('share_groups', 'share_group_snapshots'):
self.assertNotIn(key, quotas)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
def test_show_sg_quotas_for_user_using_too_old_microversion(self):
quotas = self.shares_v2_client.show_quotas(
self.tenant_id, self.user_id,
version=PRE_SHARE_GROUPS_MICROVERSION)
for key in ('share_groups', 'share_group_snapshots'):
self.assertNotIn(key, quotas)
@ddt.data(
('id', True),
('name', False),
)
@ddt.unpack
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_show_share_type_quotas(self, share_type_key, is_st_public):
# Create share type
share_type = self.create_share_type(
data_utils.rand_name("tempest-manila"),
is_public=is_st_public,
cleanup_in_class=False,
extra_specs=self.add_extra_specs_to_dict(),
)
if 'share_type' in share_type:
share_type = share_type['share_type']
# Get current project quotas
p_quotas = self.shares_v2_client.show_quotas(self.tenant_id)
# Get current quotas
st_quotas = self.shares_v2_client.show_quotas(
self.tenant_id, share_type=share_type[share_type_key])
# Share type quotas have values equal to project's
for key in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
self.assertEqual(st_quotas[key], p_quotas[key])
# Verify that we do not have share groups related quotas
# for share types.
for key in ('share_groups', 'share_group_snapshots'):
self.assertNotIn(key, st_quotas)
@ddt.ddt
class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
if not CONF.share.run_quota_tests:
msg = "Quota tests are disabled."
raise cls.skipException(msg)
super(SharesAdminQuotasUpdateTest, cls).resource_setup()
def setUp(self):
super(self.__class__, self).setUp()
self.client = self.get_client_with_isolated_creds(client_version='2')
self.tenant_id = self.client.tenant_id
self.user_id = self.client.user_id
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_tenant_quota_shares(self):
# get current quotas
quotas = self.client.show_quotas(self.tenant_id)
new_quota = int(quotas["shares"]) + 2
# set new quota for shares
updated = self.client.update_quotas(self.tenant_id, shares=new_quota)
self.assertEqual(new_quota, int(updated["shares"]))
@ddt.data(
"share_groups",
"share_group_snapshots",
)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_update_tenant_quota_share_groups(self, quota_key):
# Get current quotas
quotas = self.client.show_quotas(self.tenant_id)
new_quota = int(quotas[quota_key]) + 2
# Set new quota
updated = self.client.update_quotas(
self.tenant_id, **{quota_key: new_quota})
self.assertEqual(new_quota, int(updated[quota_key]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_user_quota_shares(self):
# get current quotas
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
new_quota = int(quotas["shares"]) - 1
# set new quota for shares
updated = self.client.update_quotas(
self.tenant_id, self.user_id, shares=new_quota)
self.assertEqual(new_quota, int(updated["shares"]))
@ddt.data(
"share_groups",
"share_group_snapshots",
)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_update_user_quota_share_groups(self, quota_key):
# Get current quotas
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
new_quota = int(quotas[quota_key]) - 1
# Set new quota
updated = self.client.update_quotas(
self.tenant_id, self.user_id, **{quota_key: new_quota})
self.assertEqual(new_quota, int(updated[quota_key]))
def _create_share_type(self):
share_type = self.create_share_type(
data_utils.rand_name("tempest-manila"),
cleanup_in_class=False,
client=self.shares_v2_client,
extra_specs=self.add_extra_specs_to_dict(),
)
if 'share_type' in share_type:
share_type = share_type['share_type']
return share_type
@ddt.data(
('id', True),
('name', False),
)
@ddt.unpack
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_update_share_type_quota(self, share_type_key, is_st_public):
share_type = self._create_share_type()
# Get current quotas
quotas = self.client.show_quotas(
self.tenant_id, share_type=share_type[share_type_key])
# Update quotas
for q in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
new_quota = int(quotas[q]) - 1
# Set new quota
updated = self.client.update_quotas(
self.tenant_id, share_type=share_type[share_type_key],
**{q: new_quota})
self.assertEqual(new_quota, int(updated[q]))
current_quotas = self.client.show_quotas(
self.tenant_id, share_type=share_type[share_type_key])
for q in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
self.assertEqual(int(quotas[q]) - 1, current_quotas[q])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_update_share_type_quota_in_two_projects(self):
"""Regression test for bug/1722707"""
share_type = self._create_share_type()
client1 = self.get_client_with_isolated_creds(client_version='2')
client2 = self.get_client_with_isolated_creds(client_version='2')
for client in (client1, client2):
# Update quotas
for q in ('shares', 'gigabytes', 'snapshots',
'snapshot_gigabytes'):
# Set new quota
updated = client.update_quotas(
client.tenant_id, share_type=share_type['id'], **{q: 0})
self.assertEqual(0, int(updated[q]))
current_quotas = client.show_quotas(
client.tenant_id, share_type=share_type['id'])
for q in ('shares', 'gigabytes', 'snapshots',
'snapshot_gigabytes'):
self.assertEqual(0, int(current_quotas[q]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_tenant_quota_snapshots(self):
# get current quotas
quotas = self.client.show_quotas(self.tenant_id)
new_quota = int(quotas["snapshots"]) + 2
# set new quota for snapshots
updated = self.client.update_quotas(
self.tenant_id, snapshots=new_quota)
self.assertEqual(new_quota, int(updated["snapshots"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_user_quota_snapshots(self):
# get current quotas
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
new_quota = int(quotas["snapshots"]) - 1
# set new quota for snapshots
updated = self.client.update_quotas(
self.tenant_id, self.user_id, snapshots=new_quota)
self.assertEqual(new_quota, int(updated["snapshots"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_tenant_quota_gigabytes(self):
# get current quotas
custom = self.client.show_quotas(self.tenant_id)
# make quotas for update
gigabytes = int(custom["gigabytes"]) + 2
# set new quota for shares
updated = self.client.update_quotas(
self.tenant_id, gigabytes=gigabytes)
self.assertEqual(gigabytes, int(updated["gigabytes"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_tenant_quota_snapshot_gigabytes(self):
# get current quotas
custom = self.client.show_quotas(self.tenant_id)
# make quotas for update
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
# set new quota for shares
updated = self.client.update_quotas(
self.tenant_id,
snapshot_gigabytes=snapshot_gigabytes)
self.assertEqual(snapshot_gigabytes,
int(updated["snapshot_gigabytes"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_user_quota_gigabytes(self):
# get current quotas
custom = self.client.show_quotas(self.tenant_id, self.user_id)
# make quotas for update
gigabytes = int(custom["gigabytes"]) - 1
# set new quota for shares
updated = self.client.update_quotas(
self.tenant_id, self.user_id, gigabytes=gigabytes)
self.assertEqual(gigabytes, int(updated["gigabytes"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_user_quota_snapshot_gigabytes(self):
# get current quotas
custom = self.client.show_quotas(self.tenant_id, self.user_id)
# make quotas for update
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) - 1
# set new quota for shares
updated = self.client.update_quotas(
self.tenant_id, self.user_id,
snapshot_gigabytes=snapshot_gigabytes)
self.assertEqual(snapshot_gigabytes,
int(updated["snapshot_gigabytes"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_tenant_quota_share_networks(self):
# get current quotas
quotas = self.client.show_quotas(self.tenant_id)
new_quota = int(quotas["share_networks"]) + 2
# set new quota for share-networks
updated = self.client.update_quotas(
self.tenant_id, share_networks=new_quota)
self.assertEqual(new_quota, int(updated["share_networks"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_user_quota_share_networks(self):
# get current quotas
quotas = self.client.show_quotas(
self.tenant_id, self.user_id)
new_quota = int(quotas["share_networks"]) - 1
# set new quota for share-networks
updated = self.client.update_quotas(
self.tenant_id, self.user_id,
share_networks=new_quota)
self.assertEqual(new_quota, int(updated["share_networks"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_reset_tenant_quotas(self):
# Get default_quotas
default = self.client.default_quotas(self.tenant_id)
# Get current quotas
custom = self.client.show_quotas(self.tenant_id)
# Make quotas for update
data = {
"shares": int(custom["shares"]) + 2,
"snapshots": int(custom["snapshots"]) + 2,
"gigabytes": int(custom["gigabytes"]) + 2,
"snapshot_gigabytes": int(custom["snapshot_gigabytes"]) + 2,
"share_networks": int(custom["share_networks"]) + 2,
}
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
CONF.share.run_share_group_tests):
data["share_groups"] = int(custom["share_groups"]) + 2
data["share_group_snapshots"] = (
int(custom["share_group_snapshots"]) + 2)
# set new quota
updated = self.client.update_quotas(self.tenant_id, **data)
self.assertEqual(data["shares"], int(updated["shares"]))
self.assertEqual(data["snapshots"], int(updated["snapshots"]))
self.assertEqual(data["gigabytes"], int(updated["gigabytes"]))
self.assertEqual(
data["snapshot_gigabytes"], int(updated["snapshot_gigabytes"]))
self.assertEqual(
data["share_networks"], int(updated["share_networks"]))
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
CONF.share.run_share_group_tests):
self.assertEqual(
data["share_groups"], int(updated["share_groups"]))
self.assertEqual(
data["share_group_snapshots"],
int(updated["share_group_snapshots"]))
# Reset customized quotas
self.client.reset_quotas(self.tenant_id)
# Verify quotas
reseted = self.client.show_quotas(self.tenant_id)
self.assertEqual(int(default["shares"]), int(reseted["shares"]))
self.assertEqual(int(default["snapshots"]), int(reseted["snapshots"]))
self.assertEqual(int(default["gigabytes"]), int(reseted["gigabytes"]))
self.assertEqual(
int(default["snapshot_gigabytes"]),
int(reseted["snapshot_gigabytes"]))
self.assertEqual(
int(default["share_networks"]), int(reseted["share_networks"]))
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
CONF.share.run_share_group_tests):
self.assertEqual(
int(default["share_groups"]), int(reseted["share_groups"]))
self.assertEqual(
int(default["share_group_snapshots"]),
int(reseted["share_group_snapshots"]))
@ddt.data(
('id', True),
('name', False),
)
@ddt.unpack
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_reset_share_type_quotas(self, share_type_key, is_st_public):
share_type = self._create_share_type()
# get default_quotas
default_quotas = self.client.default_quotas(self.tenant_id)
# set new quota for project
updated_p_quota = self.client.update_quotas(
self.tenant_id,
shares=int(default_quotas['shares']) + 5,
snapshots=int(default_quotas['snapshots']) + 5,
gigabytes=int(default_quotas['gigabytes']) + 5,
snapshot_gigabytes=int(default_quotas['snapshot_gigabytes']) + 5)
# set new quota for project
self.client.update_quotas(
self.tenant_id,
share_type=share_type[share_type_key],
shares=int(default_quotas['shares']) + 3,
snapshots=int(default_quotas['snapshots']) + 3,
gigabytes=int(default_quotas['gigabytes']) + 3,
snapshot_gigabytes=int(default_quotas['snapshot_gigabytes']) + 3)
# reset share type quotas
self.client.reset_quotas(
self.tenant_id, share_type=share_type[share_type_key])
# verify quotas
current_p_quota = self.client.show_quotas(self.tenant_id)
current_st_quota = self.client.show_quotas(
self.tenant_id, share_type=share_type[share_type_key])
for key in ('shares', 'snapshots', 'gigabytes', 'snapshot_gigabytes'):
self.assertEqual(updated_p_quota[key], current_p_quota[key])
# Default share type quotas are current project quotas
self.assertNotEqual(default_quotas[key], current_st_quota[key])
self.assertEqual(current_p_quota[key], current_st_quota[key])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_quota_for_shares(self):
self.client.update_quotas(self.tenant_id, shares=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('shares'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_user_quota_for_shares(self):
self.client.update_quotas(
self.tenant_id, self.user_id, shares=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('shares'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_quota_for_snapshots(self):
self.client.update_quotas(self.tenant_id, snapshots=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('snapshots'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_user_quota_for_snapshots(self):
self.client.update_quotas(
self.tenant_id, self.user_id, snapshots=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('snapshots'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_quota_for_gigabytes(self):
self.client.update_quotas(self.tenant_id, gigabytes=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('gigabytes'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_quota_for_snapshot_gigabytes(self):
self.client.update_quotas(
self.tenant_id, snapshot_gigabytes=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_user_quota_for_gigabytes(self):
self.client.update_quotas(
self.tenant_id, self.user_id, gigabytes=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('gigabytes'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_user_quota_for_snapshot_gigabytes(self):
self.client.update_quotas(
self.tenant_id, self.user_id, snapshot_gigabytes=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_quota_for_share_networks(self):
self.client.update_quotas(self.tenant_id, share_networks=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('share_networks'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_unlimited_user_quota_for_share_networks(self):
self.client.update_quotas(
self.tenant_id, self.user_id, share_networks=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('share_networks'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_unlimited_quota_for_share_groups(self):
self.client.update_quotas(self.tenant_id, share_groups=-1)
quotas = self.client.show_quotas(self.tenant_id)
self.assertEqual(-1, quotas.get('share_groups'))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_unlimited_user_quota_for_share_group_snapshots(self):
self.client.update_quotas(
self.tenant_id, self.user_id, share_group_snapshots=-1)
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
self.assertEqual(-1, quotas.get('share_group_snapshots'))
@ddt.data(11, -1)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_update_user_quotas_bigger_than_project_quota(self, user_quota):
self.client.update_quotas(self.tenant_id, shares=10)
self.client.update_quotas(
self.tenant_id, user_id=self.user_id, force=True,
shares=user_quota)
@ddt.data(11, -1)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_update_share_type_quotas_bigger_than_project_quota(self, st_q):
share_type = self._create_share_type()
self.client.update_quotas(self.tenant_id, shares=10)
self.client.update_quotas(
self.tenant_id, share_type=share_type['name'], force=True,
shares=st_q)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_set_share_type_quota_bigger_than_users_quota(self):
share_type = self._create_share_type()
self.client.update_quotas(self.tenant_id, force=False, shares=13)
self.client.update_quotas(
self.tenant_id, user_id=self.user_id, force=False, shares=11)
# Share type quota does not depend on user's quota, so we should be
# able to update it.
self.client.update_quotas(
self.tenant_id, share_type=share_type['name'], force=False,
shares=12)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.39")
def test_quotas_usages(self):
# Create share types
st_1, st_2 = (self._create_share_type() for i in (1, 2))
# Set quotas for project, user and both share types
self.client.update_quotas(self.tenant_id, shares=3, gigabytes=10)
self.client.update_quotas(
self.tenant_id, user_id=self.user_id, shares=2, gigabytes=7)
for st in (st_1['id'], st_2['name']):
self.client.update_quotas(
self.tenant_id, share_type=st, shares=2, gigabytes=4)
# Create share, 4Gb, st1 - ok
share_1 = self.create_share(
size=4, share_type_id=st_1['id'], client=self.client,
cleanup_in_class=False)
# Try create shares twice, failing on user and share type quotas
for size, st_id in ((3, st_1['id']), (4, st_2['id'])):
self.assertRaises(
lib_exc.OverLimit,
self.create_share,
size=size, share_type_id=st_id, client=self.client,
cleanup_in_class=False)
# Create share, 3Gb, st2 - ok
share_2 = self.create_share(
size=3, share_type_id=st_2['id'], client=self.client,
cleanup_in_class=False)
# Check quota usages
for g_l, g_use, s_l, s_use, kwargs in (
(10, 7, 3, 2, {}),
(7, 7, 2, 2, {'user_id': self.user_id}),
(4, 4, 2, 1, {'share_type': st_1['id']}),
(4, 3, 2, 1, {'share_type': st_2['name']})):
quotas = self.client.detail_quotas(
tenant_id=self.tenant_id, **kwargs)
self.assertEqual(0, quotas['gigabytes']['reserved'])
self.assertEqual(g_l, quotas['gigabytes']['limit'])
self.assertEqual(g_use, quotas['gigabytes']['in_use'])
self.assertEqual(0, quotas['shares']['reserved'])
self.assertEqual(s_l, quotas['shares']['limit'])
self.assertEqual(s_use, quotas['shares']['in_use'])
# Delete shares and then check usages
for share_id in (share_1['id'], share_2['id']):
self.client.delete_share(share_id)
self.client.wait_for_resource_deletion(share_id=share_id)
for kwargs in ({}, {'share_type': st_1['name']},
{'user_id': self.user_id}, {'share_type': st_2['id']}):
quotas = self.client.detail_quotas(
tenant_id=self.tenant_id, **kwargs)
for key in ('shares', 'gigabytes'):
self.assertEqual(0, quotas[key]['reserved'])
self.assertEqual(0, quotas[key]['in_use'])
def _check_sg_usages(self, quotas, in_use, limit):
"""Helper method for 'test_share_group_quotas_usages' test."""
self.assertEqual(0, int(quotas['share_groups']['reserved']))
self.assertEqual(in_use, int(quotas['share_groups']['in_use']))
self.assertEqual(limit, int(quotas['share_groups']['limit']))
def _check_sgs_usages(self, quotas, in_use):
"""Helper method for 'test_share_group_quotas_usages' test."""
self.assertEqual(0, int(quotas['share_group_snapshots']['reserved']))
self.assertEqual(
in_use, int(quotas['share_group_snapshots']['in_use']))
self.assertEqual(1, int(quotas['share_group_snapshots']['limit']))
def _check_usages(self, sg_in_use, sgs_in_use):
"""Helper method for 'test_share_group_quotas_usages' test."""
p_quotas = self.client.detail_quotas(tenant_id=self.tenant_id)
u_quotas = self.client.detail_quotas(
tenant_id=self.tenant_id, user_id=self.user_id)
self._check_sg_usages(p_quotas, sg_in_use, 3)
self._check_sg_usages(u_quotas, sg_in_use, 2)
self._check_sgs_usages(p_quotas, sgs_in_use)
self._check_sgs_usages(u_quotas, sgs_in_use)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
def test_share_group_quotas_usages(self):
# Set quotas for project (3 SG, 1 SGS) and user (2 SG, 1 SGS)
self.client.update_quotas(
self.tenant_id, share_groups=3, share_group_snapshots=1)
self.client.update_quotas(
self.tenant_id, user_id=self.user_id,
share_groups=2, share_group_snapshots=1)
# Check usages, they should be 0s
self._check_usages(0, 0)
# Create SG1 and check usages
share_group1 = self.create_share_group(
cleanup_in_class=False, client=self.client)
self._check_usages(1, 0)
# Create SGS1 and check usages
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
share_group1['id'], cleanup_in_class=False, client=self.client)
self._check_usages(1, 1)
# Create SG2 from SGS1 and check usages
share_group2 = self.create_share_group(
cleanup_in_class=False, client=self.client,
source_share_group_snapshot_id=sg_snapshot['id'])
self._check_usages(2, 1)
# Try create SGS2, fail, then check usages
self.assertRaises(
lib_exc.OverLimit,
self.create_share_group,
client=self.client, cleanup_in_class=False)
self._check_usages(2, 1)
# Delete SG2 and check usages
self.client.delete_share_group(share_group2['id'])
self.client.wait_for_resource_deletion(
share_group_id=share_group2['id'])
self._check_usages(1, 1)
# Delete SGS1 and check usages
self.client.delete_share_group_snapshot(sg_snapshot['id'])
self.client.wait_for_resource_deletion(
share_group_snapshot_id=sg_snapshot['id'])
self._check_usages(1, 0)
# Delete SG1 and check usages
self.client.delete_share_group(share_group1['id'])
self.client.wait_for_resource_deletion(
share_group_id=share_group1['id'])
self._check_usages(0, 0)

View File

@@ -1,357 +0,0 @@
# Copyright 2014 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
PRE_SHARE_GROUPS_MICROVERSION = "2.39"
SHARE_GROUPS_MICROVERSION = "2.40"
@ddt.ddt
class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
if not CONF.share.run_quota_tests:
msg = "Quota tests are disabled."
raise cls.skipException(msg)
super(SharesAdminQuotasNegativeTest, cls).resource_setup()
cls.user_id = cls.shares_client.user_id
cls.tenant_id = cls.shares_client.tenant_id
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_quotas_with_empty_tenant_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.show_quotas, "")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_reset_quotas_with_empty_tenant_id(self):
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.NotFound,
client.reset_quotas, "")
@ddt.data(
{"shares": -2},
{"snapshots": -2},
{"gigabytes": -2},
{"snapshot_gigabytes": -2},
{"share_networks": -2},
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_update_quota_with_wrong_data(self, kwargs):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas, client.tenant_id, **kwargs)
@ddt.data(
{"share_groups": -2},
{"share_group_snapshots": -2},
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_update_sg_quota_with_wrong_data(self, kwargs):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds(client_version='2')
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas, client.tenant_id, **kwargs)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_with_size_bigger_than_quota(self):
quotas = self.shares_client.show_quotas(
self.shares_client.tenant_id)
overquota = int(quotas['gigabytes']) + 2
# try schedule share with size, bigger than gigabytes quota
self.assertRaises(lib_exc.OverLimit,
self.create_share,
size=overquota)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_create_share_group_with_exceeding_quota_limit(self):
client = self.get_client_with_isolated_creds(client_version='2')
client.update_quotas(client.tenant_id, share_groups=0)
# Try schedule share group creation
self.assertRaises(
lib_exc.OverLimit,
self.create_share_group,
client=client,
cleanup_in_class=False)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_set_user_quota_shares_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for shares bigger than tenant quota
bigger_value = int(tenant_quotas["shares"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
force=False,
shares=bigger_value)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_set_user_quota_snaps_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for snapshots bigger than tenant quota
bigger_value = int(tenant_quotas["snapshots"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
force=False,
snapshots=bigger_value)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_set_user_quota_gigabytes_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for gigabytes bigger than tenant quota
bigger_value = int(tenant_quotas["gigabytes"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
force=False,
gigabytes=bigger_value)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_set_user_quota_snap_gigabytes_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for snapshot gigabytes bigger than tenant quota
bigger_value = int(tenant_quotas["snapshot_gigabytes"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
force=False,
snapshot_gigabytes=bigger_value)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_set_user_quota_share_networks_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for share_networks bigger than tenant quota
bigger_value = int(tenant_quotas["share_networks"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
force=False,
share_networks=bigger_value)
@ddt.data(
('quota-sets', '2.0', 'show_quotas'),
('quota-sets', '2.0', 'default_quotas'),
('quota-sets', '2.0', 'reset_quotas'),
('quota-sets', '2.0', 'update_quotas'),
('quota-sets', '2.6', 'show_quotas'),
('quota-sets', '2.6', 'default_quotas'),
('quota-sets', '2.6', 'reset_quotas'),
('quota-sets', '2.6', 'update_quotas'),
('os-quota-sets', '2.7', 'show_quotas'),
('os-quota-sets', '2.7', 'default_quotas'),
('os-quota-sets', '2.7', 'reset_quotas'),
('os-quota-sets', '2.7', 'update_quotas'),
)
@ddt.unpack
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_not_supported("2.7")
def test_show_quotas_with_wrong_versions(self, url, version, method_name):
self.assertRaises(
lib_exc.NotFound,
getattr(self.shares_v2_client, method_name),
self.shares_v2_client.tenant_id,
version=version, url=url,
)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_show_quota_detail_with_wrong_versions(self):
version = '2.24'
url = 'quota-sets'
self.assertRaises(
lib_exc.NotFound,
self.shares_v2_client.detail_quotas,
self.shares_v2_client.tenant_id,
version=version, url=url,
)
@ddt.data('show', 'reset', 'update')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_share_type_quotas_using_nonexistent_share_type(self, op):
client = self.get_client_with_isolated_creds(client_version='2')
kwargs = {"share_type": "fake_nonexistent_share_type"}
if op == 'update':
tenant_quotas = client.show_quotas(client.tenant_id)
kwargs['shares'] = tenant_quotas['shares']
self.assertRaises(
lib_exc.NotFound,
getattr(client, op + '_quotas'),
client.tenant_id,
**kwargs)
def _create_share_type(self):
share_type = self.create_share_type(
data_utils.rand_name("tempest-manila"),
cleanup_in_class=False,
client=self.shares_v2_client,
extra_specs=self.add_extra_specs_to_dict(),
)
if 'share_type' in share_type:
share_type = share_type['share_type']
return share_type
@ddt.data('id', 'name')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_try_update_share_type_quota_for_share_networks(self, key):
client = self.get_client_with_isolated_creds(client_version='2')
share_type = self._create_share_type()
tenant_quotas = client.show_quotas(client.tenant_id)
# Try to set 'share_networks' quota for share type
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
share_type=share_type[key],
share_networks=int(tenant_quotas["share_networks"]),
)
@ddt.data('share_groups', 'share_group_snapshots')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
def test_try_update_share_type_quota_for_share_groups(self, quota_name):
client = self.get_client_with_isolated_creds(client_version='2')
share_type = self._create_share_type()
tenant_quotas = client.show_quotas(client.tenant_id)
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
share_type=share_type["name"],
**{quota_name: int(tenant_quotas[quota_name])}
)
@ddt.data('share_groups', 'share_group_snapshots')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
@base.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
def test_share_group_quotas_using_too_old_microversion(self, quota_key):
client = self.get_client_with_isolated_creds(client_version='2')
tenant_quotas = client.show_quotas(
client.tenant_id, version=SHARE_GROUPS_MICROVERSION)
kwargs = {
"version": PRE_SHARE_GROUPS_MICROVERSION,
quota_key: tenant_quotas[quota_key],
}
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
**kwargs)
@ddt.data('show', 'reset', 'update')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.38")
def test_share_type_quotas_using_too_old_microversion(self, op):
client = self.get_client_with_isolated_creds(client_version='2')
share_type = self._create_share_type()
kwargs = {"version": "2.38", "share_type": share_type["name"]}
if op == 'update':
tenant_quotas = client.show_quotas(client.tenant_id)
kwargs['shares'] = tenant_quotas['shares']
self.assertRaises(
lib_exc.BadRequest,
getattr(client, op + '_quotas'),
client.tenant_id,
**kwargs)
@ddt.data('show', 'reset', 'update')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_quotas_providing_share_type_and_user_id(self, op):
client = self.get_client_with_isolated_creds(client_version='2')
share_type = self._create_share_type()
kwargs = {"share_type": share_type["name"], "user_id": client.user_id}
if op == 'update':
tenant_quotas = client.show_quotas(client.tenant_id)
kwargs['shares'] = tenant_quotas['shares']
self.assertRaises(
lib_exc.BadRequest,
getattr(client, op + '_quotas'),
client.tenant_id,
**kwargs)
@ddt.data(11, -1)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@base.skip_if_microversion_lt("2.39")
def test_update_share_type_quotas_bigger_than_project_quota(self, st_q):
client = self.get_client_with_isolated_creds(client_version='2')
share_type = self._create_share_type()
client.update_quotas(client.tenant_id, shares=10)
self.assertRaises(
lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
share_type=share_type['name'],
force=False,
shares=st_q)

View File

@@ -1,183 +0,0 @@
# Copyright 2015 Yogesh Kshirsagar
# 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.
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
CONF = config.CONF
_MIN_SUPPORTED_MICROVERSION = '2.11'
@testtools.skipUnless(CONF.share.run_replication_tests,
'Replication tests are disabled.')
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
class ReplicationAdminTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ReplicationAdminTest, cls).resource_setup()
# Create share_type
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.replication_type = CONF.share.backend_replication_type
if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
raise share_exceptions.ShareReplicationTypeException(
replication_type=cls.replication_type
)
cls.zones = cls.get_availability_zones(client=cls.admin_client)
cls.share_zone = cls.zones[0]
cls.replica_zone = cls.zones[-1]
cls.extra_specs = cls.add_extra_specs_to_dict(
{"replication_type": cls.replication_type})
share_type = cls.create_share_type(
name,
extra_specs=cls.extra_specs,
client=cls.admin_client)
cls.share_type = share_type["share_type"]
# Create share with above share_type
cls.share = cls.create_share(share_type_id=cls.share_type["id"],
availability_zone=cls.share_zone,
client=cls.admin_client)
cls.replica = cls.admin_client.list_share_replicas(
share_id=cls.share['id'])[0]
@staticmethod
def _filter_share_replica_list(replica_list, r_state):
# Iterate through replica list to filter based on replica_state
return [replica['id'] for replica in replica_list
if replica['replica_state'] == r_state]
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_promote_out_of_sync_share_replica(self):
"""Test promote 'out_of_sync' share replica to active state."""
if (self.replication_type
not in constants.REPLICATION_PROMOTION_CHOICES):
msg = "Option backend_replication_type should be one of (%s)!"
raise self.skipException(
msg % ','.join(constants.REPLICATION_PROMOTION_CHOICES))
share = self.create_share(
share_type_id=self.share_type['id'], client=self.admin_client)
original_replica = self.admin_client.list_share_replicas(
share_id=share['id'])[0]
# NOTE(Yogi1): Cleanup needs to be disabled for replica that is
# being promoted since it will become the 'primary'/'active' replica.
replica = self.create_share_replica(
share["id"], self.replica_zone, cleanup=False,
client=self.admin_client)
# Wait for replica state to update after creation
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.REPLICATION_STATE_IN_SYNC,
status_attr='replica_state')
# List replicas
replica_list = self.admin_client.list_share_replicas(
share_id=share['id'])
# Check if there is only 1 'active' replica before promotion.
active_replicas = self._filter_share_replica_list(
replica_list, constants.REPLICATION_STATE_ACTIVE)
self.assertEqual(1, len(active_replicas))
# Set replica_state to 'out_of_sync'
self.admin_client.reset_share_replica_state(
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
status_attr='replica_state')
# Promote 'out_of_sync' replica to 'active' state.
self.promote_share_replica(replica['id'], self.admin_client)
# Original replica will need to be cleaned up before the promoted
# replica can be deleted.
self.addCleanup(self.delete_share_replica, original_replica['id'])
# Check if there is still only 1 'active' replica after promotion.
replica_list = self.admin_client.list_share_replicas(
share_id=self.share["id"])
new_active_replicas = self._filter_share_replica_list(
replica_list, constants.REPLICATION_STATE_ACTIVE)
self.assertEqual(1, len(new_active_replicas))
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_force_delete_share_replica(self):
"""Test force deleting a replica that is in 'error_deleting' status."""
replica = self.create_share_replica(self.share['id'],
self.replica_zone,
cleanup_in_class=False,
client=self.admin_client)
self.admin_client.reset_share_replica_status(
replica['id'], constants.STATUS_ERROR_DELETING)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.STATUS_ERROR_DELETING)
self.admin_client.force_delete_share_replica(replica['id'])
self.admin_client.wait_for_resource_deletion(replica_id=replica['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_reset_share_replica_status(self):
"""Test resetting a replica's 'status' attribute."""
replica = self.create_share_replica(self.share['id'],
self.replica_zone,
cleanup_in_class=False,
client=self.admin_client)
self.admin_client.reset_share_replica_status(replica['id'],
constants.STATUS_ERROR)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.STATUS_ERROR)
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_reset_share_replica_state(self):
"""Test resetting a replica's 'replica_state' attribute."""
replica = self.create_share_replica(self.share['id'],
self.replica_zone,
cleanup_in_class=False,
client=self.admin_client)
self.admin_client.reset_share_replica_state(replica['id'],
constants.STATUS_ERROR)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.STATUS_ERROR, status_attr='replica_state')
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_resync_share_replica(self):
"""Test resyncing a replica."""
replica = self.create_share_replica(self.share['id'],
self.replica_zone,
cleanup_in_class=False,
client=self.admin_client)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.REPLICATION_STATE_IN_SYNC,
status_attr='replica_state')
# Set replica_state to 'out_of_sync'.
self.admin_client.reset_share_replica_state(
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
status_attr='replica_state')
# Attempt resync
self.admin_client.resync_share_replica(replica['id'])
self.admin_client.wait_for_share_replica_status(
replica['id'], constants.REPLICATION_STATE_IN_SYNC,
status_attr='replica_state')

View File

@@ -1,179 +0,0 @@
# 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.
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
CONF = config.CONF
_MIN_SUPPORTED_MICROVERSION = '2.11'
@testtools.skipUnless(CONF.share.run_replication_tests,
'Replication tests are disabled.')
@testtools.skipIf(
CONF.share.multitenancy_enabled,
"Only for driver_handles_share_servers = False driver mode.")
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
class ReplicationAdminTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ReplicationAdminTest, cls).resource_setup()
# Create share_type
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.replication_type = CONF.share.backend_replication_type
if cls.replication_type not in constants.REPLICATION_TYPE_CHOICES:
raise share_exceptions.ShareReplicationTypeException(
replication_type=cls.replication_type
)
cls.zones = cls.get_availability_zones(client=cls.admin_client)
cls.share_zone = cls.zones[0]
cls.replica_zone = cls.zones[-1]
cls.extra_specs = cls.add_extra_specs_to_dict(
{"replication_type": cls.replication_type})
share_type = cls.create_share_type(
name,
cleanup_in_class=True,
extra_specs=cls.extra_specs,
client=cls.admin_client)
cls.share_type = share_type["share_type"]
# Create share with above share_type
cls.share = cls.create_share(size=CONF.share.share_size+1,
share_type_id=cls.share_type["id"],
availability_zone=cls.share_zone,
client=cls.admin_client)
cls.replica = cls.admin_client.list_share_replicas(
share_id=cls.share['id'])[0]
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_extend_tests,
'Extend share tests are disabled.')
def test_extend_replicated_share(self):
# Test extend share
new_size = self.share["size"] + 1
self.admin_client.extend_share(self.share["id"], new_size)
self.admin_client.wait_for_share_status(self.share["id"],
"available")
share = self.admin_client.get_share(self.share["id"])
self.assertEqual(new_size, int(share["size"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_shrink_tests,
'Shrink share tests are disabled.')
def test_shrink_replicated_share(self):
share = self.admin_client.get_share(self.share["id"])
new_size = self.share["size"] - 1
self.admin_client.shrink_share(self.share["id"], new_size)
self.admin_client.wait_for_share_status(share["id"], "available")
shrink_share = self.admin_client.get_share(self.share["id"])
self.assertEqual(new_size, int(shrink_share["size"]))
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@testtools.skipUnless(CONF.share.run_manage_unmanage_tests,
'Manage/Unmanage Tests are disabled.')
def test_manage_share_for_replication_type(self):
"""Manage a share with replication share type."""
# Create a share and unmanage it
share = self.create_share(size=2,
share_type_id=self.share_type["id"],
availability_zone=self.share_zone,
cleanup_in_class=True,
client=self.admin_client)
share = self.admin_client.get_share(share["id"])
export_locations = self.admin_client.list_share_export_locations(
share["id"])
export_path = export_locations[0]['path']
self.admin_client.unmanage_share(share['id'])
self.admin_client.wait_for_resource_deletion(share_id=share['id'])
# Manage the previously unmanaged share
managed_share = self.admin_client.manage_share(
share['host'], share['share_proto'],
export_path, self.share_type['id'])
self.admin_client.wait_for_share_status(
managed_share['id'], 'available')
# Add managed share to cleanup queue
self.method_resources.insert(
0, {'type': 'share', 'id': managed_share['id'],
'client': self.admin_client})
# Make sure a replica can be added to newly managed share
self.create_share_replica(managed_share['id'], self.replica_zone,
cleanup=True, client=self.admin_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_manage_unmanage_tests,
'Manage/Unmanage Tests are disabled.')
def test_unmanage_replicated_share_with_replica(self):
"""Try to unmanage a share having replica."""
# Create a share replica before unmanaging the share
self.create_share_replica(self.share["id"], self.replica_zone,
cleanup=True, client=self.admin_client)
self.assertRaises(
lib_exc.Conflict,
self.admin_client.unmanage_share,
share_id=self.share['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@testtools.skipUnless(CONF.share.run_manage_unmanage_tests,
'Manage/Unmanage Tests are disabled.')
def test_unmanage_replicated_share_with_no_replica(self):
"""Unmanage a replication type share that does not have replica."""
share = self.create_share(size=2,
share_type_id=self.share_type["id"],
availability_zone=self.share_zone,
client=self.admin_client)
self.admin_client.unmanage_share(share['id'])
self.admin_client.wait_for_resource_deletion(share_id=share['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_manage_unmanage_snapshot_tests,
'Manage/Unmanage Snapshot Tests are disabled.')
def test_manage_replicated_share_snapshot(self):
"""Try to manage a snapshot of the replicated."""
# Create a share replica before managing the snapshot
self.create_share_replica(self.share["id"], self.replica_zone,
cleanup=True, client=self.admin_client)
self.assertRaises(
lib_exc.Conflict,
self.admin_client.manage_snapshot,
share_id=self.share['id'],
provider_location="127.0.0.1:/fake_provider_location/"
"manila_share_9dc61f49_fbc8_48d7_9337_2f9593d9")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipUnless(CONF.share.run_manage_unmanage_snapshot_tests,
'Manage/Unmanage Snapshot Tests are disabled.')
def test_unmanage_replicated_share_snapshot(self):
"""Try to unmanage a snapshot of the replicated share with replica."""
# Create a share replica before unmanaging the snapshot
self.create_share_replica(self.share["id"], self.replica_zone,
cleanup=True, client=self.admin_client)
snapshot = self.create_snapshot_wait_for_active(
self.share["id"], client=self.admin_client)
self.assertRaises(
lib_exc.Conflict,
self.admin_client.unmanage_snapshot,
snapshot_id=snapshot['id'])

View File

@@ -1,204 +0,0 @@
# Copyright (c) 2015 Clinton Knight. 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@ddt.ddt
class SchedulerStatsAdminTest(base.BaseSharesAdminTest):
@classmethod
def _create_share_type(cls, negative=False):
name = data_utils.rand_name("unique_st_name")
extra_specs = None
if negative:
extra_specs = {
'share_backend_name': data_utils.rand_name("fake_name"),
}
extra_specs = cls.add_extra_specs_to_dict(extra_specs=extra_specs)
return cls.create_share_type(
name, extra_specs=extra_specs,
client=cls.admin_client)
@classmethod
def resource_setup(cls):
super(SchedulerStatsAdminTest, cls).resource_setup()
cls.admin_client = cls.shares_v2_client
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_pool_list(self):
# List pools
pool_response = self.shares_client.list_pools()
pool_list = pool_response.get('pools')
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
required_keys = {'name', 'host', 'backend', 'pool'}
actual_keys = set(pool.keys())
self.assertTrue(actual_keys.issuperset(required_keys))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_pool_list_with_filters(self):
# List pools
pool_response = self.shares_client.list_pools()
pool_list = pool_response.get('pools')
# Ensure we got at least one pool
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
# Build search opts from data and get pools again with filter
search_opts = {
'host': self._wrap_regex_for_exact_match(pool.get('host')),
'backend': self._wrap_regex_for_exact_match(pool.get('backend')),
'pool': self._wrap_regex_for_exact_match(pool.get('pool')),
}
pool_response = self.shares_client.list_pools(
search_opts=search_opts)
filtered_pool_list = pool_response.get('pools')
# Ensure we got exactly one pool matching the first one from above
self.assertEqual(1, len(filtered_pool_list))
# Match the key values, not the timestamp.
for k, v in search_opts.items():
self.assertEqual(v[1:-1], filtered_pool_list[0][k])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_pool_list_with_filters_negative(self):
# Build search opts for a non-existent pool
search_opts = {
'host': 'foo',
'backend': 'bar',
'pool': 'shark',
}
pool_response = self.shares_client.list_pools(
search_opts=search_opts)
pool_list = pool_response.get('pools')
# Ensure we got no pools
self.assertEmpty(pool_list)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_pool_list_detail(self):
# List pools
pool_response = self.shares_client.list_pools(detail=True)
pool_list = pool_response.get('pools')
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
required_keys = {'name', 'host', 'backend', 'pool', 'capabilities'}
actual_keys = set(pool.keys())
self.assertTrue(actual_keys.issuperset(required_keys))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_pool_list_detail_with_filters(self):
# List pools
pool_response = self.shares_client.list_pools(detail=True)
pool_list = pool_response.get('pools')
# Ensure we got at least one pool
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
# Build search opts from data and get pools again with filter
search_opts = {
'host': self._wrap_regex_for_exact_match(pool.get('host')),
'backend': self._wrap_regex_for_exact_match(pool.get('backend')),
'pool': self._wrap_regex_for_exact_match(pool.get('pool')),
}
pool_response = self.shares_client.list_pools(
detail=True, search_opts=search_opts)
filtered_pool_list = pool_response.get('pools')
# Ensure we got exactly one pool matching the first one from above
self.assertEqual(1, len(filtered_pool_list))
# Match the key values, not the timestamp.
for k, v in search_opts.items():
self.assertEqual(v[1:-1], filtered_pool_list[0][k])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_pool_list_detail_with_filters_negative(self):
# Build search opts for a non-existent pool
search_opts = {
'host': 'foo',
'backend': 'bar',
'pool': 'shark',
}
pool_response = self.shares_client.list_pools(
detail=True, search_opts=search_opts)
pool_list = pool_response.get('pools')
# Ensure we got no pools
self.assertEmpty(pool_list)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.23")
@ddt.data((True, "name"), (True, "id"), (False, "name"), (False, "id"))
@ddt.unpack
def test_pool_list_with_share_type_filter_with_detail(
self, detail, share_type_key):
st = self._create_share_type()
search_opts = {"share_type": st["share_type"][share_type_key]}
kwargs = {'search_opts': search_opts}
if detail:
kwargs.update({'detail': True})
pools = self.admin_client.list_pools(**kwargs)['pools']
self.assertIsNotNone(pools, 'No pools returned from pools API')
self.assertNotEmpty(pools)
for pool in pools:
pool_keys = list(pool.keys())
self.assertIn("name", pool_keys)
self.assertIn("host", pool_keys)
self.assertIn("backend", pool_keys)
self.assertIn("pool", pool_keys)
self.assertIs(detail, "capabilities" in pool_keys)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.23")
@ddt.data((True, "name"), (True, "id"), (False, "name"), (False, "id"))
@ddt.unpack
def test_pool_list_with_share_type_filter_with_detail_negative(
self, detail, share_type_key):
st_negative = self._create_share_type(negative=True)
search_opts = {"share_type": st_negative["share_type"][share_type_key]}
pools = self.admin_client.list_pools(
detail=detail, search_opts=search_opts)['pools']
self.assertEmpty(pools)
def _wrap_regex_for_exact_match(self, regex):
return '^%s$' % regex

View File

@@ -1,64 +0,0 @@
# Copyright 2014 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.
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.api import test_security_services
class SecurityServiceAdminTest(
base.BaseSharesAdminTest,
test_security_services.SecurityServiceListMixin):
def setUp(self):
super(SecurityServiceAdminTest, self).setUp()
ss_ldap_data = {
'name': 'ss_ldap',
'dns_ip': '1.1.1.1',
'server': 'fake_server_1',
'domain': 'fake_domain_1',
'user': 'fake_user',
'password': 'pass',
}
ss_kerberos_data = {
'name': 'ss_kerberos',
'dns_ip': '2.2.2.2',
'server': 'fake_server_2',
'domain': 'fake_domain_2',
'user': 'test_user',
'password': 'word',
}
self.ss_ldap = self.create_security_service('ldap', **ss_ldap_data)
self.ss_kerberos = self.create_security_service(
'kerberos',
**ss_kerberos_data)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_list_security_services_all_tenants(self):
listed = self.shares_client.list_security_services(
params={'all_tenants': 1})
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
self.assertTrue(any(self.ss_kerberos['id'] == ss['id']
for ss in listed))
keys = ["name", "id", "status", "type", ]
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_security_services_invalid_filters(self):
listed = self.shares_client.list_security_services(
params={'fake_opt': 'some_value'})
self.assertEqual(0, len(listed))

View File

@@ -1,105 +0,0 @@
# Copyright 2014 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.
import ddt
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
@ddt.ddt
class ServicesAdminTest(base.BaseSharesAdminTest):
def setUp(self):
super(ServicesAdminTest, self).setUp()
self.services = self.shares_client.list_services()
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_list_services(self, client_name):
services = getattr(self, client_name).list_services()
self.assertNotEqual(0, len(services))
for service in services:
self.assertIsNotNone(service['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_host_name(self, client_name):
host = self.services[0]["host"]
params = {"host": host}
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(host, service["host"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_binary_name(self, client_name):
binary = self.services[0]["binary"]
params = {"binary": binary, }
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(binary, service["binary"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_availability_zone(self, client_name):
zone = self.services[0]["zone"]
params = {"zone": zone, }
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(zone, service["zone"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_status(self, client_name):
status = self.services[0]["status"]
params = {"status": status, }
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(status, service["status"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_state(self, client_name):
state = self.services[0]["state"]
params = {"state": state, }
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(state, service["state"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('shares_client', 'shares_v2_client')
def test_get_services_by_all_filters(self, client_name):
params = {
"host": self.services[0]["host"],
"binary": self.services[0]["binary"],
"zone": self.services[0]["zone"],
"status": self.services[0]["status"],
"state": self.services[0]["state"],
}
services = getattr(self, client_name).list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(params["host"], service["host"])
self.assertEqual(params["binary"], service["binary"])
self.assertEqual(params["zone"], service["zone"])
self.assertEqual(params["status"], service["status"])
self.assertEqual(params["state"], service["state"])

View File

@@ -1,100 +0,0 @@
# Copyright 2014 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.
import ddt
from tempest.lib import exceptions as lib_exc
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
@ddt.ddt
class ServicesAdminNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ServicesAdminNegativeTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_services_with_non_admin_user(self):
self.assertRaises(lib_exc.Forbidden,
self.member_client.list_services)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_params(self):
# All services are expected if send the request with invalid parameter
services = self.admin_client.list_services()
params = {'fake_param': 'fake_param_value'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(len(services), len(services_fake))
# "update_at" field could be updated before second request,
# so do not take it in account.
for service in services + services_fake:
service["updated_at"] = "removed_possible_difference"
msg = ('Unexpected service list. Expected %s, got %s.' %
(services, services_fake))
self.assertEqual(sorted(services, key=lambda service: service['id']),
sorted(services_fake,
key=lambda service: service['id']),
msg)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_host(self):
params = {'host': 'fake_host'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(0, len(services_fake))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_binary(self):
params = {'binary': 'fake_binary'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(0, len(services_fake))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_zone(self):
params = {'zone': 'fake_zone'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(0, len(services_fake))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_status(self):
params = {'status': 'fake_status'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(0, len(services_fake))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_service_by_invalid_state(self):
params = {'state': 'fake_state'}
services_fake = self.admin_client.list_services(params)
self.assertEqual(0, len(services_fake))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@ddt.data(
('os-services', '2.7'),
('services', '2.6'),
('services', '2.0'),
)
@ddt.unpack
@base.skip_if_microversion_not_supported("2.7")
def test_list_services_with_wrong_versions(self, url, version):
self.assertRaises(
lib_exc.NotFound,
self.admin_client.list_services,
version=version, url=url,
)

View File

@@ -1,245 +0,0 @@
# Copyright 2016 Andrew Kerr
# 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.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
@ddt.ddt
class ShareGroupTypesTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareGroupTypesTest, cls).resource_setup()
# Create 2 share_types
name = data_utils.rand_name("tempest-manila")
extra_specs = cls.add_extra_specs_to_dict()
share_type = cls.create_share_type(name, extra_specs=extra_specs)
cls.share_type = share_type['share_type']
name = data_utils.rand_name("tempest-manila")
share_type = cls.create_share_type(name, extra_specs=extra_specs)
cls.share_type2 = share_type['share_type']
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('id', 'name')
def test_create_get_delete_share_group_type_min(self, st_key):
name = data_utils.rand_name("tempest-manila")
# Create share group type
sg_type_c = self.create_share_group_type(
name=name,
share_types=self.share_type[st_key],
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertEqual(
[self.share_type['id']],
sg_type_c['share_types'],
'Share type not applied correctly.')
# Read share group type
sg_type_r = self.shares_v2_client.get_share_group_type(sg_type_c['id'])
keys = set(sg_type_r.keys())
self.assertTrue(
constants.SHARE_GROUP_TYPE_REQUIRED_KEYS.issubset(keys),
'At least one expected key missing from share group type '
'response. Expected %s, got %s.' % (
constants.SHARE_GROUP_TYPE_REQUIRED_KEYS, keys))
self.assertEqual(sg_type_c['name'], sg_type_r['name'])
# Delete share group type
self.shares_v2_client.delete_share_group_type(
sg_type_r['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.shares_v2_client.wait_for_resource_deletion(
share_group_type_id=sg_type_r['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@ddt.data('id', 'name')
def test_create_share_group_type_multiple_share_types_min(self, st_key):
name = data_utils.rand_name("tempest-manila")
sg_type = self.create_share_group_type(
name=name,
share_types=[self.share_type[st_key], self.share_type2[st_key]],
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertEqual(
{self.share_type['id'], self.share_type2['id']},
set(sg_type['share_types']),
'Share types not applied correctly.')
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_create_share_group_type_with_one_spec_min(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {'key': 'value'}
sg_type = self.create_share_group_type(
name=name,
share_types=self.share_type['id'],
group_specs=group_specs,
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertDictMatch(group_specs, sg_type['group_specs'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_create_share_group_type_with_multiple_specs_min(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {'key1': 'value1', 'key2': 'value2'}
sg_type = self.create_share_group_type(
name=name,
share_types=self.share_type['id'],
group_specs=group_specs,
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertDictMatch(group_specs, sg_type['group_specs'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_single_share_group_type_spec_min(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {'key1': 'value1', 'key2': 'value2'}
sg_type = self.create_share_group_type(
name=name,
share_types=self.share_type['id'],
group_specs=group_specs,
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertDictMatch(group_specs, sg_type['group_specs'])
group_specs = {'key1': 'value1', 'key2': 'value2'}
self.shares_v2_client.update_share_group_type_spec(
sg_type['id'], 'key1', 'value3')
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
self.assertIn('key1', sg_type['group_specs'])
self.assertIn('key2', sg_type['group_specs'])
self.assertEqual('value3', sg_type['group_specs']['key1'])
self.assertEqual(group_specs['key2'], sg_type['group_specs']['key2'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_all_share_group_type_specs_min(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {'key1': 'value1', 'key2': 'value2'}
sg_type = self.create_share_group_type(
name=name,
share_types=self.share_type['id'],
group_specs=group_specs,
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertDictMatch(group_specs, sg_type['group_specs'])
group_specs = {'key1': 'value3', 'key2': 'value4'}
self.shares_v2_client.update_share_group_type_specs(
sg_type['id'], group_specs)
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
for k, v in group_specs.items():
self.assertIn(k, sg_type['group_specs'])
self.assertEqual(v, sg_type['group_specs'][k])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_delete_single_share_group_type_spec_min(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {'key1': 'value1', 'key2': 'value2'}
sg_type = self.create_share_group_type(
name=name,
share_types=self.share_type['id'],
group_specs=group_specs,
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
self.assertDictMatch(group_specs, sg_type['group_specs'])
key_to_delete = 'key1'
group_specs.pop(key_to_delete)
self.shares_v2_client.delete_share_group_type_spec(
sg_type['id'], key_to_delete)
sg_type = self.shares_v2_client.get_share_group_type(
sg_type['id'])
self.assertDictMatch(group_specs, sg_type['group_specs'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_private_share_group_type_access(self):
name = data_utils.rand_name("tempest-manila")
group_specs = {"key1": "value1", "key2": "value2"}
project_id = self.shares_v2_client.tenant_id
# Create private share group type
sgt_create = self.create_share_group_type(
name=name,
share_types=[self.share_type['id']],
is_public=False,
group_specs=group_specs,
)
self.assertEqual(name, sgt_create['name'])
sgt_id = sgt_create["id"]
# It should not be listed without access
sgt_list = self.shares_v2_client.list_share_group_types()
self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
# List projects that have access for share group type - none expected
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
self.assertEmpty(access)
# Add project access to share group type
access = self.shares_v2_client.add_access_to_share_group_type(
sgt_id, project_id)
# Now it should be listed
sgt_list = self.shares_v2_client.list_share_group_types()
self.assertTrue(any(sgt_id == sgt["id"] for sgt in sgt_list))
# List projects that have access for share group type - one expected
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
expected = [{'share_group_type_id': sgt_id, 'project_id': project_id}]
self.assertEqual(expected, access)
# Remove project access from share group type
access = self.shares_v2_client.remove_access_from_share_group_type(
sgt_id, project_id)
# It should not be listed without access
sgt_list = self.shares_v2_client.list_share_group_types()
self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
# List projects that have access for share group type - none expected
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
self.assertEmpty(access)

View File

@@ -1,146 +0,0 @@
# 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.
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
class ShareGroupTypesAdminNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ShareGroupTypesAdminNegativeTest, cls).resource_setup()
cls.share_type = cls.create_share_type(
data_utils.rand_name("unique_st_name"),
extra_specs=cls.add_extra_specs_to_dict({"key": "value"}),
client=cls.admin_shares_v2_client)
cls.share_group_type = cls.create_share_group_type(
data_utils.rand_name("unique_sgt_name"),
share_types=[cls.share_type['share_type']['id']],
client=cls.admin_shares_v2_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_group_type_without_name(self):
self.assertRaises(
lib_exc.BadRequest,
self.admin_shares_v2_client.create_share_group_type,
name=None,
share_types=data_utils.rand_name("fake"))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_group_type_with_nonexistent_share_type(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_shares_v2_client.create_share_group_type,
name=data_utils.rand_name("sgt_name_should_have_not_been_created"),
share_types=data_utils.rand_name("fake"))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_group_type_with_empty_name(self):
self.assertRaises(
lib_exc.BadRequest,
self.create_share_group_type, '',
client=self.admin_shares_v2_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_group_type_with_too_big_name(self):
self.assertRaises(
lib_exc.BadRequest,
self.create_share_group_type,
"x" * 256, client=self.admin_shares_v2_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_create_share_group_type_with_wrong_value_for_group_specs(self):
self.assertRaises(
lib_exc.BadRequest,
self.admin_shares_v2_client.create_share_group_type,
name=data_utils.rand_name("tempest_manila"),
share_types=[self.share_type['share_type']['id']],
group_specs="expecting_error_code_400")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_get_share_group_type_using_nonexistent_id(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_shares_v2_client.get_share_group_type,
data_utils.rand_name("fake"))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_delete_share_group_type_using_nonexistent_id(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_shares_v2_client.delete_share_group_type,
data_utils.rand_name("fake"))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_create_duplicate_of_share_group_type(self):
unique_name = data_utils.rand_name("unique_sgt_name")
list_of_ids = set()
for step in (1, 2):
sg_type = self.create_share_group_type(
unique_name,
share_types=[self.share_type['share_type']['id']],
client=self.admin_shares_v2_client,
cleanup_in_class=False)
self.assertRaises(
lib_exc.Conflict,
self.create_share_group_type,
unique_name,
share_types=[self.share_type['share_type']['id']],
client=self.admin_shares_v2_client)
list_of_ids.add(sg_type['id'])
self.assertEqual(unique_name, sg_type['name'])
self.admin_shares_v2_client.delete_share_group_type(sg_type['id'])
self.assertEqual(2, len(list_of_ids))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_add_project_access_to_public_share_group_type(self):
self.assertRaises(
lib_exc.Conflict,
self.admin_shares_v2_client.add_access_to_share_group_type,
self.share_group_type["id"],
self.admin_shares_v2_client.tenant_id)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_remove_project_access_from_public_share_group_type(self):
self.assertRaises(
lib_exc.Conflict,
self.admin_shares_v2_client.remove_access_from_share_group_type,
self.share_group_type["id"],
self.admin_shares_v2_client.tenant_id)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_add_project_access_to_nonexistent_share_group_type(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_shares_v2_client.add_access_to_share_group_type,
data_utils.rand_name("fake"),
self.admin_shares_v2_client.tenant_id)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_remove_project_access_from_nonexistent_share_group_type(self):
self.assertRaises(
lib_exc.NotFound,
self.admin_shares_v2_client.remove_access_from_share_group_type,
data_utils.rand_name("fake"),
self.admin_shares_v2_client.tenant_id)

View File

@@ -1,191 +0,0 @@
# Copyright 2016 Andrew Kerr
# 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.
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
class ShareGroupsTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareGroupsTest, cls).resource_setup()
# Create 2 share_types
name = data_utils.rand_name("tempest-manila")
extra_specs = cls.add_extra_specs_to_dict()
share_type = cls.create_share_type(name, extra_specs=extra_specs)
cls.share_type = share_type['share_type']
name = data_utils.rand_name("tempest-manila")
share_type = cls.create_share_type(name, extra_specs=extra_specs)
cls.share_type2 = share_type['share_type']
cls.sg_type = cls.create_share_group_type(
name=name,
share_types=[cls.share_type['id'], cls.share_type2['id']],
cleanup_in_class=True,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_single_share_type_min(self):
share_group = self.create_share_group(
share_group_type_id=self.sg_type['id'],
cleanup_in_class=False,
share_type_ids=[self.share_type['id']],
version=constants.MIN_SHARE_GROUP_MICROVERSION)
keys = set(share_group.keys())
self.assertTrue(
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
'At least one expected element missing from share group '
'response. Expected %(expected)s, got %(actual)s.' % {
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
"actual": keys})
actual_sg_type = share_group['share_group_type_id']
expected_sg_type = self.sg_type['id']
self.assertEqual(
expected_sg_type, actual_sg_type,
'Incorrect share group type applied to share group '
'%s. Expected %s, got %s' % (
share_group['id'], expected_sg_type, actual_sg_type))
actual_share_types = share_group['share_types']
expected_share_types = [self.share_type['id']]
self.assertEqual(
sorted(expected_share_types),
sorted(actual_share_types),
'Incorrect share types applied to share group %s. '
'Expected %s, got %s' % (
share_group['id'], expected_share_types, actual_share_types))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_multiple_share_types_min(self):
share_group = self.create_share_group(
share_group_type_id=self.sg_type['id'],
cleanup_in_class=False,
share_type_ids=[self.share_type['id'], self.share_type2['id']],
version=constants.MIN_SHARE_GROUP_MICROVERSION)
keys = set(share_group.keys())
self.assertTrue(
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
'At least one expected element missing from share group '
'response. Expected %(expected)s, got %(actual)s.' % {
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
"actual": keys})
actual_sg_type = share_group['share_group_type_id']
expected_sg_type = self.sg_type['id']
self.assertEqual(
expected_sg_type, actual_sg_type,
'Incorrect share group type applied to share group %s. '
'Expected %s, got %s' % (
share_group['id'], expected_sg_type, actual_sg_type))
actual_share_types = share_group['share_types']
expected_share_types = [self.share_type['id'], self.share_type2['id']]
self.assertEqual(
sorted(expected_share_types),
sorted(actual_share_types),
'Incorrect share types applied to share group %s. '
'Expected %s, got %s' % (
share_group['id'], expected_share_types, actual_share_types))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_default_share_group_type_applied(self):
default_type = self.shares_v2_client.get_default_share_group_type()
default_share_types = default_type['share_types']
share_group = self.create_share_group(
cleanup_in_class=False,
share_type_ids=default_share_types,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
keys = set(share_group.keys())
self.assertTrue(
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
'At least one expected element missing from share group '
'response. Expected %(expected)s, got %(actual)s.' % {
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
"actual": keys})
actual_sg_type = share_group['share_group_type_id']
expected_sg_type = default_type['id']
self.assertEqual(
expected_sg_type, actual_sg_type,
'Incorrect share group type applied to share group %s. '
'Expected %s, got %s' % (
share_group['id'], expected_sg_type, actual_sg_type))
@testtools.skipUnless(
CONF.share.multitenancy_enabled, "Only for multitenancy.")
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_sg_from_snapshot_verify_share_server_information_min(self):
# Create a share group
orig_sg = self.create_share_group(
share_group_type_id=self.sg_type['id'],
cleanup_in_class=False,
share_type_ids=[self.share_type['id']],
version=constants.MIN_SHARE_GROUP_MICROVERSION)
# Get latest share group information
orig_sg = self.shares_v2_client.get_share_group(
orig_sg['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
# Assert share server information
self.assertIsNotNone(orig_sg['share_network_id'])
self.assertIsNotNone(orig_sg['share_server_id'])
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
orig_sg['id'], cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
new_sg = self.create_share_group(
share_group_type_id=self.sg_type['id'],
cleanup_in_class=False,
version=constants.MIN_SHARE_GROUP_MICROVERSION,
source_share_group_snapshot_id=sg_snapshot['id'])
# Assert share server information
self.assertEqual(
orig_sg['share_network_id'], new_sg['share_network_id'])
self.assertEqual(
orig_sg['share_server_id'], new_sg['share_server_id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_sg_with_sg_type_but_without_any_group_specs(self):
# Create share group type not specifying any group specs
sg_type = self.create_share_group_type(
name=data_utils.rand_name("tempest-manila"),
share_types=[self.share_type['id']],
group_specs={},
cleanup_in_class=False)
# Create share group, it should be created always, because we do not
# restrict choice anyhow.
self.create_share_group(
share_type_ids=[self.share_type['id']],
share_group_type_id=sg_type['id'],
cleanup_in_class=False)

View File

@@ -1,56 +0,0 @@
# Copyright 2017 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.
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
class ShareGroupsNegativeTest(base.BaseSharesAdminTest):
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_wrong_consistent_snapshot_spec(self):
# Create valid share type for share group type
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_extra_specs_to_dict()
st = self.create_share_type(name, extra_specs=extra_specs)
share_type = st['share_type'] if 'share_type' in st else st
# Create share group type with wrong value for
# 'consistent_snapshot_support' capability, we always expect
# NoValidHostFound using this SG type.
sg_type = self.create_share_group_type(
name=name,
share_types=[share_type['id']],
group_specs={"consistent_snapshot_support": "fake"},
cleanup_in_class=False)
# Try create share group
self.assertRaises(
share_exceptions.ShareGroupBuildErrorException,
self.create_share_group,
share_type_ids=[share_type['id']],
share_group_type_id=sg_type['id'],
cleanup_in_class=False)

View File

@@ -1,114 +0,0 @@
# Copyright 2015 Andrew Kerr
# 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.
import ddt
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
@ddt.ddt
class ShareInstancesTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareInstancesTest, cls).resource_setup()
cls.share = cls.create_share()
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_get_instances_of_share_v2_3(self):
"""Test that we get only the 1 share instance back for the share."""
share_instances = self.shares_v2_client.get_instances_of_share(
self.share['id'], version='2.3'
)
self.assertEqual(1, len(share_instances),
'Too many share instances found; expected 1, '
'found %s' % len(share_instances))
si = share_instances[0]
self.assertEqual(self.share['id'], si['share_id'],
'Share instance %s has incorrect share id value; '
'expected %s, got %s.' % (si['id'],
self.share['id'],
si['share_id']))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_instances_v2_3(self):
"""Test that we list the share instance back."""
share_instances = self.shares_v2_client.list_share_instances(
version='2.3'
)
share_ids = [si['share_id'] for si in share_instances]
msg = 'Share instance for share %s was not found.' % self.share['id']
self.assertIn(self.share['id'], share_ids, msg)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@ddt.data('2.3', '2.9', '2.10', '2.30')
def test_get_share_instance(self, version):
"""Test that we get the proper keys back for the instance."""
share_instances = self.shares_v2_client.get_instances_of_share(
self.share['id'], version=version,
)
si = self.shares_v2_client.get_share_instance(
share_instances[0]['id'], version=version)
expected_keys = [
'host', 'share_id', 'id', 'share_network_id', 'status',
'availability_zone', 'share_server_id', 'created_at',
]
if utils.is_microversion_lt(version, '2.9'):
expected_keys.extend(["export_location", "export_locations"])
if utils.is_microversion_ge(version, '2.10'):
expected_keys.append("access_rules_status")
if utils.is_microversion_ge(version, '2.11'):
expected_keys.append("replica_state")
if utils.is_microversion_ge(version, '2.22'):
expected_keys.append("share_type_id")
if utils.is_microversion_ge(version, '2.30'):
expected_keys.append("cast_rules_to_readonly")
expected_keys = sorted(expected_keys)
actual_keys = sorted(si.keys())
self.assertEqual(expected_keys, actual_keys,
'Share instance %s returned incorrect keys; '
'expected %s, got %s.' % (
si['id'], expected_keys, actual_keys))
@ddt.data('path', 'id')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.35")
def test_list_share_instances_with_export_location_path_and_id(
self, export_location_type):
share_instances_except = (
self.shares_v2_client.get_instances_of_share(
self.share['id']))
export_locations = (
self.shares_v2_client.list_share_instance_export_locations(
share_instances_except[0]['id']))
filters = {
'export_location_' + export_location_type:
export_locations[0][export_location_type],
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters)
self.assertEqual(1, len(share_instances))
self.assertEqual(share_instances_except[0]['id'],
share_instances[0]['id'])

View File

@@ -1,54 +0,0 @@
# 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.
import ddt
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
@ddt.ddt
class ShareInstancesNegativeTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareInstancesNegativeTest, cls).resource_setup()
cls.share = cls.create_share()
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.34")
@ddt.data('path', 'id')
def test_list_share_instances_with_export_location_and_invalid_version(
self, export_location_type):
# In API versions <v2.35, querying the share instance API by export
# location path or ID should have no effect. Those filters were
# supported from v2.35
filters = {
'export_location_' + export_location_type: 'fake',
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters, version="2.34")
self.assertGreater(len(share_instances), 0)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.35")
@ddt.data('path', 'id')
def test_list_share_instances_with_export_location_not_exist(
self, export_location_type):
filters = {
'export_location_' + export_location_type: 'fake_not_exist',
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters)
self.assertEqual(0, len(share_instances))

View File

@@ -1,252 +0,0 @@
# Copyright 2015 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.
import six
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
class ManageNFSShareTest(base.BaseSharesAdminTest):
protocol = 'nfs'
# NOTE(vponomaryov): be careful running these tests using generic driver
# because cinder volumes will stay attached to service Nova VM and
# won't be deleted.
@classmethod
@testtools.skipIf(
CONF.share.multitenancy_enabled,
"Only for driver_handles_share_servers = False driver mode.")
@testtools.skipUnless(
CONF.share.run_manage_unmanage_tests,
"Manage/unmanage tests are disabled.")
def resource_setup(cls):
super(ManageNFSShareTest, cls).resource_setup()
if cls.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled" % cls.protocol
raise cls.skipException(message)
# Create share types
cls.st_name = data_utils.rand_name("manage-st-name")
cls.st_name_invalid = data_utils.rand_name("manage-st-name-invalid")
cls.extra_specs = {
'storage_protocol': CONF.share.capability_storage_protocol,
'driver_handles_share_servers': False,
'snapshot_support': six.text_type(
CONF.share.capability_snapshot_support),
'create_share_from_snapshot_support': six.text_type(
CONF.share.capability_create_share_from_snapshot_support)
}
cls.extra_specs_invalid = {
'storage_protocol': CONF.share.capability_storage_protocol,
'driver_handles_share_servers': True,
'snapshot_support': six.text_type(
CONF.share.capability_snapshot_support),
'create_share_from_snapshot_support': six.text_type(
CONF.share.capability_create_share_from_snapshot_support),
}
cls.st = cls.create_share_type(
name=cls.st_name,
cleanup_in_class=True,
extra_specs=cls.extra_specs)
cls.st_invalid = cls.create_share_type(
name=cls.st_name_invalid,
cleanup_in_class=True,
extra_specs=cls.extra_specs_invalid)
def _test_manage(self, is_public=False,
version=CONF.share.max_api_microversion,
check_manage=False):
share = self._create_share_for_manage()
name = "Name for 'managed' share that had ID %s" % share['id']
description = "Description for 'managed' share"
# Unmanage share
self._unmanage_share_and_wait(share)
if check_manage:
# After 'unmanage' operation, share instance should be deleted.
# Assert not related to 'manage' test, but placed here for
# resource optimization.
share_instance_list = self.shares_v2_client.list_share_instances()
share_ids = [si['share_id'] for si in share_instance_list]
self.assertNotIn(share['id'], share_ids)
# Manage share
managed_share = self.shares_v2_client.manage_share(
service_host=share['host'],
export_path=share['export_locations'][0],
protocol=share['share_proto'],
share_type_id=self.st['share_type']['id'],
name=name,
description=description,
is_public=is_public,
version=version,
)
# Add managed share to cleanup queue
self.method_resources.insert(
0, {'type': 'share', 'id': managed_share['id'],
'client': self.shares_client})
# Wait for success
self.shares_v2_client.wait_for_share_status(managed_share['id'],
'available')
# Verify data of managed share
self.assertEqual(name, managed_share['name'])
self.assertEqual(description, managed_share['description'])
self.assertEqual(share['host'], managed_share['host'])
self.assertEqual(share['share_proto'], managed_share['share_proto'])
if utils.is_microversion_ge(version, "2.6"):
self.assertEqual(self.st['share_type']['id'],
managed_share['share_type'])
else:
self.assertEqual(self.st['share_type']['name'],
managed_share['share_type'])
if utils.is_microversion_ge(version, "2.8"):
self.assertEqual(is_public, managed_share['is_public'])
else:
self.assertFalse(managed_share['is_public'])
if utils.is_microversion_ge(version, "2.16"):
self.assertEqual(share['user_id'], managed_share['user_id'])
else:
self.assertNotIn('user_id', managed_share)
# Delete share
self.shares_v2_client.delete_share(managed_share['id'])
self.shares_v2_client.wait_for_resource_deletion(
share_id=managed_share['id'])
self.assertRaises(lib_exc.NotFound,
self.shares_v2_client.get_share,
managed_share['id'])
def _create_share_for_manage(self):
creation_data = {
'share_type_id': self.st['share_type']['id'],
'share_protocol': self.protocol,
}
share = self.create_share(**creation_data)
share = self.shares_v2_client.get_share(share['id'])
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.9"):
el = self.shares_v2_client.list_share_export_locations(share["id"])
share["export_locations"] = el
return share
def _unmanage_share_and_wait(self, share):
self.shares_v2_client.unmanage_share(share['id'])
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.5")
def test_manage_with_os_share_manage_url(self):
self._test_manage(version="2.5")
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.8")
def test_manage_with_is_public_True(self):
self._test_manage(is_public=True, version="2.8")
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.16")
def test_manage_show_user_id(self):
self._test_manage(version="2.16")
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_manage(self):
self._test_manage(check_manage=True)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_manage_invalid(self):
# Try to manage share with invalid parameters, it should not succeed
# because the scheduler will reject it. If it succeeds, then this test
# case failed. Then, in order to remove the resource from backend, we
# need to manage it again, properly, so we can delete it. Consequently
# the second part of this test also tests that manage operation with a
# proper share type works.
def _delete_share(share_id):
self.shares_v2_client.reset_state(share_id)
self.shares_v2_client.delete_share(share_id)
self.shares_v2_client.wait_for_resource_deletion(share_id=share_id)
self.assertRaises(lib_exc.NotFound,
self.shares_v2_client.get_share,
share_id)
share = self._create_share_for_manage()
self._unmanage_share_and_wait(share)
managed_share = self.shares_v2_client.manage_share(
service_host=share['host'],
export_path=share['export_locations'][0],
protocol=share['share_proto'],
share_type_id=self.st_invalid['share_type']['id'])
self.addCleanup(_delete_share, managed_share['id'])
self.shares_v2_client.wait_for_share_status(
managed_share['id'], 'manage_error')
managed_share = self.shares_v2_client.get_share(managed_share['id'])
self.assertEqual(1, int(managed_share['size']))
# Delete resource from backend. We need to manage the share properly
# so it can be removed.
managed_share = self.shares_v2_client.manage_share(
service_host=share['host'],
export_path=share['export_locations'][0],
protocol=share['share_proto'],
share_type_id=self.st['share_type']['id'])
self.addCleanup(_delete_share, managed_share['id'])
self.shares_v2_client.wait_for_share_status(
managed_share['id'], 'available')
class ManageCIFSShareTest(ManageNFSShareTest):
protocol = 'cifs'
class ManageGLUSTERFSShareTest(ManageNFSShareTest):
protocol = 'glusterfs'
class ManageHDFSShareTest(ManageNFSShareTest):
protocol = 'hdfs'
class ManageCephFSShareTest(ManageNFSShareTest):
protocol = 'cephfs'
class ManageMapRFSShareTest(ManageNFSShareTest):
protocol = 'maprfs'

View File

@@ -1,95 +0,0 @@
# Copyright 2014 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.
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.api import test_share_networks
class ShareNetworkAdminTest(
base.BaseSharesAdminTest,
test_share_networks.ShareNetworkListMixin):
@classmethod
def resource_setup(cls):
super(ShareNetworkAdminTest, cls).resource_setup()
ss_data = cls.generate_security_service_data()
cls.ss_ldap = cls.create_security_service(**ss_data)
cls.data_sn_with_ldap_ss = {
'name': 'sn_with_ldap_ss',
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'created_at': '2002-02-02',
'updated_at': None,
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'description': 'fake description',
}
cls.sn_with_ldap_ss = cls.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_ldap_ss)
cls.shares_client.add_sec_service_to_share_network(
cls.sn_with_ldap_ss["id"],
cls.ss_ldap["id"])
cls.isolated_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
cls.data_sn_with_kerberos_ss = {
'name': 'sn_with_kerberos_ss',
'created_at': '2003-03-03',
'updated_at': None,
'neutron_net_id': 'test net id',
'neutron_subnet_id': 'test subnet id',
'network_type': 'local',
'segmentation_id': 2000,
'cidr': '10.0.0.0/13',
'ip_version': 6,
'description': 'fake description',
}
cls.ss_kerberos = cls.isolated_client.create_security_service(
ss_type='kerberos',
**cls.data_sn_with_ldap_ss)
cls.sn_with_kerberos_ss = cls.isolated_client.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_kerberos_ss)
cls.isolated_client.add_sec_service_to_share_network(
cls.sn_with_kerberos_ss["id"],
cls.ss_kerberos["id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_list_share_networks_all_tenants(self):
listed = self.shares_client.list_share_networks_with_detail(
{'all_tenants': 1})
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
for sn in listed))
self.assertTrue(any(self.sn_with_kerberos_ss['id'] == sn['id']
for sn in listed))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_list_share_networks_filter_by_project_id(self):
listed = self.shares_client.list_share_networks_with_detail(
{'project_id': self.sn_with_kerberos_ss['project_id']})
self.assertTrue(any(self.sn_with_kerberos_ss['id'] == sn['id']
for sn in listed))
self.assertTrue(all(self.sn_with_kerberos_ss['project_id'] ==
sn['project_id'] for sn in listed))

View File

@@ -1,258 +0,0 @@
# Copyright 2014 OpenStack Foundation
# 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.
import re
import ddt
import six
from tempest import config
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.multitenancy_enabled,
'Share servers can be tested only with multitenant drivers.')
@ddt.ddt
class ShareServersAdminTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareServersAdminTest, cls).resource_setup()
cls.share = cls.create_share()
cls.share_network = cls.shares_v2_client.get_share_network(
cls.shares_v2_client.share_network_id)
if not cls.share_network["name"]:
sn_id = cls.share_network["id"]
cls.share_network = cls.shares_v2_client.update_share_network(
sn_id, name="sn_%s" % sn_id)
cls.sn_name_and_id = [
cls.share_network["name"],
cls.share_network["id"],
]
# Date should be like '2014-13-12T11:10:09.000000'
cls.date_re = re.compile("^([0-9]{4}-[0-9]{2}-[0-9]{2}[A-Z]{1}"
"[0-9]{2}:[0-9]{2}:[0-9]{2}).*$")
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_without_filters(self):
servers = self.shares_v2_client.list_share_servers()
self.assertGreater(len(servers), 0)
keys = [
"id",
"host",
"status",
"share_network_name",
"updated_at",
"project_id",
]
for server in servers:
# All expected keys are present
for key in keys:
self.assertIn(key, server.keys())
# 'Updated at' is valid date if set
if server["updated_at"]:
self.assertTrue(self.date_re.match(server["updated_at"]))
# Host is not empty
self.assertGreater(len(server["host"]), 0)
# Id is not empty
self.assertGreater(len(server["id"]), 0)
# Project id is not empty
self.assertGreater(len(server["project_id"]), 0)
# Do not verify statuses because we get all share servers from whole
# cluster and here can be servers with any state.
# Server we used is present.
any(s["share_network_name"] in self.sn_name_and_id for s in servers)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_with_host_filter(self):
# Get list of share servers and remember 'host' name
servers = self.shares_v2_client.list_share_servers()
# Remember name of server that was used by this test suite
# to be sure it will be still existing.
for server in servers:
if server["share_network_name"] in self.sn_name_and_id:
if not server["host"]:
msg = ("Server '%s' has wrong value for host - "
"'%s'.") % (server["id"], server["host"])
raise lib_exc.InvalidContentType(message=msg)
host = server["host"]
break
else:
msg = ("Appropriate server was not found. Its share_network_data"
": '%s'. List of servers: '%s'.") % (self.sn_name_and_id,
six.text_type(servers))
raise lib_exc.NotFound(message=msg)
search_opts = {"host": host}
servers = self.shares_v2_client.list_share_servers(search_opts)
self.assertGreater(len(servers), 0)
for server in servers:
self.assertEqual(server["host"], host)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_with_status_filter(self):
search_opts = {"status": "active"}
servers = self.shares_v2_client.list_share_servers(search_opts)
# At least 1 share server should exist always - the one created
# for this class.
self.assertGreater(len(servers), 0)
for server in servers:
self.assertEqual(server["status"], "active")
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_with_project_id_filter(self):
search_opts = {"project_id": self.share_network["project_id"]}
servers = self.shares_v2_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertGreater(len(servers), 0)
for server in servers:
self.assertEqual(server["project_id"],
self.share_network["project_id"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_with_share_network_name_filter(self):
search_opts = {"share_network": self.share_network["name"]}
servers = self.shares_v2_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertGreater(len(servers), 0)
for server in servers:
self.assertEqual(server["share_network_name"],
self.share_network["name"])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_share_servers_with_share_network_id_filter(self):
search_opts = {"share_network": self.share_network["id"]}
servers = self.shares_v2_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertGreater(len(servers), 0)
for server in servers:
self.assertIn(server["share_network_name"],
self.sn_name_and_id)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_show_share_server(self):
share = self.shares_v2_client.get_share(self.share["id"])
server = self.shares_v2_client.show_share_server(
share["share_server_id"])
keys = [
"id",
"host",
"project_id",
"status",
"share_network_name",
"created_at",
"updated_at",
"backend_details",
]
# all expected keys are present
for key in keys:
self.assertIn(key, server.keys())
# 'created_at' is valid date
self.assertTrue(self.date_re.match(server["created_at"]))
# 'updated_at' is valid date if set
if server["updated_at"]:
self.assertTrue(self.date_re.match(server["updated_at"]))
# veriy that values for following keys are not empty
for k in ('host', 'id', 'project_id', 'status', 'share_network_name'):
self.assertGreater(len(server[k]), 0)
# 'backend_details' should be a dict
self.assertIsInstance(server["backend_details"], dict)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_show_share_server_details(self):
share = self.shares_v2_client.get_share(self.share['id'])
details = self.shares_v2_client.show_share_server_details(
share['share_server_id'])
# If details are present they and their values should be only strings
for k, v in details.items():
self.assertIsInstance(k, six.string_types)
self.assertIsInstance(v, six.string_types)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(True, False)
@testtools.skipIf(CONF.share.share_network_id != "",
"This test is not suitable for pre-existing "
"share_network.")
def test_delete_share_server(self, delete_share_network):
# Get network and subnet from existing share_network and reuse it
# to be able to delete share_server after test ends.
# TODO(vponomaryov): attach security-services too. If any exist from
# donor share-network.
new_sn = self.create_share_network(
neutron_net_id=self.share_network['neutron_net_id'],
neutron_subnet_id=self.share_network['neutron_subnet_id'])
# Create server with share
self.create_share(share_network_id=new_sn['id'])
# List share servers, filtered by share_network_id
servers = self.shares_v2_client.list_share_servers(
{"share_network": new_sn["id"]})
# There can be more than one share server for share network when retry
# was used and share was created successfully not from first time.
# So, iterate all share-servers, release all created resources. It will
# allow share network to be deleted in cleanup.
for serv in servers:
# Verify that filtering worked as expected.
self.assertEqual(new_sn["id"], serv["share_network_id"])
# List shares by share server id
shares = self.shares_v2_client.list_shares_with_detail(
{"share_server_id": serv["id"]})
for s in shares:
self.assertEqual(new_sn["id"], s["share_network_id"])
# Delete shares, so we will have share server without shares
for s in shares:
self.shares_v2_client.delete_share(s["id"])
# Wait for shares deletion
for s in shares:
self.shares_v2_client.wait_for_resource_deletion(
share_id=s["id"])
# List shares by share server id, we expect empty list
empty = self.shares_v2_client.list_shares_with_detail(
{"share_server_id": serv["id"]})
self.assertEqual(0, len(empty))
if delete_share_network:
# Delete share network, it should trigger share server deletion
self.shares_v2_client.delete_share_network(new_sn["id"])
else:
# Delete share server
self.shares_v2_client.delete_share_server(serv["id"])
# Wait for share server deletion
self.shares_v2_client.wait_for_resource_deletion(
server_id=serv["id"])
if delete_share_network:
self.shares_v2_client.wait_for_resource_deletion(
sn_id=new_sn["id"])

View File

@@ -1,108 +0,0 @@
# Copyright 2014 OpenStack Foundation
# 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.
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
class ShareServersNegativeAdminTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(ShareServersNegativeAdminTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_list_share_servers_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_client.list_share_servers)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_show_share_server_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_client.show_share_server,
'fake_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_try_show_share_server_details_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_client.show_share_server_details,
'fake_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_show_share_server_with_inexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.show_share_server,
'fake_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_show_share_server_details_with_inexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.show_share_server_details,
'fake_id')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_wrong_filter_key(self):
search_opts = {'fake_filter_key': 'ACTIVE'}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_wrong_filter_value(self):
search_opts = {'host': 123}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_fake_status(self):
search_opts = {"status": data_utils.rand_name("fake_status")}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_fake_host(self):
search_opts = {"host": data_utils.rand_name("fake_host")}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_fake_project(self):
search_opts = {"project_id": data_utils.rand_name("fake_project_id")}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_list_share_servers_with_fake_share_network(self):
search_opts = {
"share_network": data_utils.rand_name("fake_share_network"),
}
servers = self.admin_client.list_share_servers(search_opts)
self.assertEqual(0, len(servers))
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_delete_share_server_with_nonexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.admin_client.delete_share_server,
"fake_nonexistent_share_server_id")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
def test_delete_share_server_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_client.delete_share_server,
"fake_nonexistent_share_server_id")

View File

@@ -1,121 +0,0 @@
# Copyright 2016 Huawei
# 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.
import ddt
from tempest import config
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(CONF.share.run_snapshot_tests,
'Snapshot tests are disabled.')
@base.skip_if_microversion_lt("2.19")
@ddt.ddt
class ShareSnapshotInstancesTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareSnapshotInstancesTest, cls).resource_setup()
cls.share = cls.create_share()
snap = cls.create_snapshot_wait_for_active(cls.share["id"])
cls.snapshot = cls.shares_v2_client.get_snapshot(snap['id'])
@ddt.data(True, False)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_snapshot_instances_by_snapshot(self, detail):
"""Test that we get only the 1 snapshot instance from snapshot."""
snapshot_instances = self.shares_v2_client.list_snapshot_instances(
detail=detail, snapshot_id=self.snapshot['id'])
expected_keys = ['id', 'snapshot_id', 'status']
if detail:
extra_detail_keys = ['provider_location', 'share_id',
'share_instance_id', 'created_at',
'updated_at', 'progress']
expected_keys.extend(extra_detail_keys)
si_num = len(snapshot_instances)
self.assertEqual(1, si_num,
'Incorrect amount of snapshot instances found; '
'expected 1, found %s.' % si_num)
si = snapshot_instances[0]
self.assertEqual(self.snapshot['id'], si['snapshot_id'],
'Snapshot instance %s has incorrect snapshot id;'
' expected %s, got %s.' % (si['id'],
self.snapshot['id'],
si['snapshot_id']))
if detail:
self.assertEqual(self.snapshot['share_id'], si['share_id'])
for key in si:
self.assertIn(key, expected_keys)
self.assertEqual(len(expected_keys), len(si))
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_snapshot_instances(self):
"""Test that we get at least the snapshot instance."""
snapshot_instances = self.shares_v2_client.list_snapshot_instances()
snapshot_ids = [si['snapshot_id'] for si in snapshot_instances]
msg = ('Snapshot instance for snapshot %s was not found.' %
self.snapshot['id'])
self.assertIn(self.snapshot['id'], snapshot_ids, msg)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_get_snapshot_instance(self):
instances = self.shares_v2_client.list_snapshot_instances(
snapshot_id=self.snapshot['id'])
instance_detail = self.shares_v2_client.get_snapshot_instance(
instance_id=instances[0]['id'])
expected_keys = (
'id', 'created_at', 'updated_at', 'progress', 'provider_location',
'share_id', 'share_instance_id', 'snapshot_id', 'status',
)
for key in instance_detail:
self.assertIn(key, expected_keys)
self.assertEqual(len(expected_keys), len(instance_detail))
self.assertEqual(self.snapshot['id'], instance_detail['snapshot_id'])
self.assertEqual(self.snapshot['share_id'],
instance_detail['share_id'])
self.assertEqual(self.snapshot['provider_location'],
instance_detail['provider_location'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_reset_snapshot_instance_status_and_delete(self):
"""Test resetting a snapshot instance's status attribute."""
snapshot = self.create_snapshot_wait_for_active(self.share["id"])
snapshot_instances = self.shares_v2_client.list_snapshot_instances(
snapshot_id=snapshot['id'])
sii = snapshot_instances[0]['id']
for status in ("error", "available"):
self.shares_v2_client.reset_snapshot_instance_status(
sii, status=status)
self.shares_v2_client.wait_for_snapshot_instance_status(
sii, expected_status=status)
self.shares_v2_client.delete_snapshot(snapshot['id'])
self.shares_v2_client.wait_for_resource_deletion(
snapshot_id=snapshot['id'])

View File

@@ -1,88 +0,0 @@
# Copyright 2016 Huawei
# 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.
from tempest import config
from tempest.lib import exceptions as lib_exc
import testtools
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(CONF.share.run_snapshot_tests,
'Snapshot tests are disabled.')
@base.skip_if_microversion_lt("2.19")
class SnapshotInstancesNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
super(SnapshotInstancesNegativeTest, cls).resource_setup()
cls.admin_client = cls.admin_shares_v2_client
cls.member_client = cls.shares_v2_client
cls.share = cls.create_share(client=cls.admin_client)
cls.snapshot = cls.create_snapshot_wait_for_active(
cls.share["id"], client=cls.admin_client)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_list_snapshot_instances_with_snapshot_by_non_admin(self):
self.assertRaises(
lib_exc.Forbidden,
self.member_client.list_snapshot_instances,
snapshot_id=self.snapshot['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_get_snapshot_instance_by_non_admin(self):
instances = self.admin_client.list_snapshot_instances(
snapshot_id=self.snapshot['id'])
self.assertRaises(
lib_exc.Forbidden,
self.member_client.get_snapshot_instance,
instance_id=instances[0]['id'])
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_reset_snapshot_instance_status_by_non_admin(self):
instances = self.admin_client.list_snapshot_instances(