Merge "Remove in-tree tempest plugin"
This commit is contained in:
commit
11bf61f5ba
19
.zuul.yaml
19
.zuul.yaml
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,6 +0,0 @@
|
||||
====================
|
||||
Tempest Integration
|
||||
====================
|
||||
|
||||
This directory contains Tempest tests to cover Manila project.
|
||||
|
@ -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)
|
@ -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',
|
||||
}
|
@ -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()
|
@ -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."),
|
||||
]
|
@ -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]
|
@ -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']
|
@ -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']
|
@ -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)
|
@ -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
@ -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")
|
@ -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')
|
@ -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')
|
@ -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'])
|
||||
)
|
@ -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",
|
||||
)
|
@ -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)
|
@ -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)
|
@ -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"])
|
@ -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)
|
@ -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)
|
@ -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')
|
@ -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'])
|
@ -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
|
@ -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))
|
@ -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"])
|
@ -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,
|
||||
)
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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'])
|
@ -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))
|
@ -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'
|
@ -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))
|
@ -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"])
|
@ -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")
|
@ -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'])
|
@ -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(
|
||||
snapshot_id=self.snapshot['id'])
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.member_client.reset_snapshot_instance_status,
|
||||
instances[0]['id'],
|
||||
'error')
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
'Snapshot tests are disabled.')
|
||||
@base.skip_if_microversion_lt("2.19")
|
||||
class SnapshotInstancesNegativeNoResourceTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SnapshotInstancesNegativeNoResourceTest, 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_get_snapshot_instance_with_non_existent_instance(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.admin_client.get_snapshot_instance,
|
||||
instance_id="nonexistent_instance")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_snapshot_instances_by_non_admin(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.member_client.list_snapshot_instances)
|
@ -1,207 +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 ddt
|
||||
from tempest import config
|
||||
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
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_share_type_create_delete(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = self.add_extra_specs_to_dict()
|
||||
|
||||
# Create share type
|
||||
st_create = self.shares_v2_client.create_share_type(
|
||||
name, extra_specs=extra_specs)
|
||||
self.assertEqual(name, st_create['share_type']['name'])
|
||||
st_id = st_create['share_type']['id']
|
||||
|
||||
# Delete share type
|
||||
self.shares_v2_client.delete_share_type(st_id)
|
||||
|
||||
# Verify deletion of share type
|
||||
self.shares_v2_client.wait_for_resource_deletion(st_id=st_id)
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_type,
|
||||
st_id)
|
||||
|
||||
def _verify_is_public_key_name(self, share_type, version):
|
||||
old_key_name = 'os-share-type-access:is_public'
|
||||
new_key_name = 'share_type_access:is_public'
|
||||
if utils.is_microversion_gt(version, "2.6"):
|
||||
self.assertIn(new_key_name, share_type)
|
||||
self.assertNotIn(old_key_name, share_type)
|
||||
else:
|
||||
self.assertIn(old_key_name, share_type)
|
||||
self.assertNotIn(new_key_name, share_type)
|
||||
|
||||
def _verify_description(self, expect_des, share_type, version):
|
||||
if utils.is_microversion_ge(version, "2.41"):
|
||||
self.assertEqual(expect_des, share_type['description'])
|
||||
else:
|
||||
self.assertNotIn('description', share_type)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data('2.0', '2.6', '2.7', '2.40', '2.41')
|
||||
def test_share_type_create_get(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
description = None
|
||||
if utils.is_microversion_ge(version, "2.41"):
|
||||
description = "Description for share type"
|
||||
extra_specs = self.add_extra_specs_to_dict({"key": "value", })
|
||||
|
||||
# Create share type
|
||||
st_create = self.create_share_type(
|
||||
name, extra_specs=extra_specs, version=version,
|
||||
description=description)
|
||||
self.assertEqual(name, st_create['share_type']['name'])
|
||||
self._verify_description(
|
||||
description, st_create['share_type'], version)
|
||||
self._verify_is_public_key_name(st_create['share_type'], version)
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# Get share type
|
||||
get = self.shares_v2_client.get_share_type(st_id, version=version)
|
||||
self.assertEqual(name, get["share_type"]["name"])
|
||||
self.assertEqual(st_id, get["share_type"]["id"])
|
||||
self._verify_description(description, get['share_type'], version)
|
||||
self.assertEqual(extra_specs, get["share_type"]["extra_specs"])
|
||||
self._verify_is_public_key_name(get['share_type'], version)
|
||||
|
||||
# Check that backwards compatibility didn't break
|
||||
self.assertDictMatch(get["volume_type"], get["share_type"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data('2.0', '2.6', '2.7', '2.40', '2.41')
|
||||
def test_share_type_create_list(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
description = None
|
||||
if utils.is_microversion_ge(version, "2.41"):
|
||||
description = "Description for share type"
|
||||
extra_specs = self.add_extra_specs_to_dict()
|
||||
|
||||
# Create share type
|
||||
st_create = self.create_share_type(
|
||||
name, extra_specs=extra_specs, version=version,
|
||||
description=description)
|
||||
self._verify_is_public_key_name(st_create['share_type'], version)
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# list share types
|
||||
st_list = self.shares_v2_client.list_share_types(version=version)
|
||||
sts = st_list["share_types"]
|
||||
self.assertGreaterEqual(len(sts), 1)
|
||||
self.assertTrue(any(st_id in st["id"] for st in sts))
|
||||
for st in sts:
|
||||
self._verify_is_public_key_name(st, version)
|
||||
|
||||
# Check that backwards compatibility didn't break
|
||||
vts = st_list["volume_types"]
|
||||
self.assertEqual(len(sts), len(vts))
|
||||
for i in range(len(sts)):
|
||||
self.assertDictMatch(sts[i], vts[i])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_with_share_type(self):
|
||||
|
||||
# Data
|
||||
share_name = data_utils.rand_name("share")
|
||||
shr_type_name = data_utils.rand_name("share-type")
|
||||
extra_specs = self.add_extra_specs_to_dict({
|
||||
"storage_protocol": CONF.share.capability_storage_protocol,
|
||||
})
|
||||
|
||||
# Create share type
|
||||
st_create = self.create_share_type(
|
||||
shr_type_name, extra_specs=extra_specs)
|
||||
|
||||
# Create share with share type
|
||||
share = self.create_share(
|
||||
name=share_name, share_type_id=st_create["share_type"]["id"])
|
||||
self.assertEqual(share["name"], share_name)
|
||||
self.shares_client.wait_for_share_status(share["id"], "available")
|
||||
|
||||
# Verify share info
|
||||
get = self.shares_v2_client.get_share(share["id"], version="2.5")
|
||||
self.assertEqual(share_name, get["name"])
|
||||
self.assertEqual(share["id"], get["id"])
|
||||
self.assertEqual(shr_type_name, get["share_type"])
|
||||
|
||||
get = self.shares_v2_client.get_share(share["id"], version="2.6")
|
||||
self.assertEqual(st_create["share_type"]["id"], get["share_type"])
|
||||
self.assertEqual(shr_type_name, get["share_type_name"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_private_share_type_access(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = self.add_extra_specs_to_dict({"key": "value", })
|
||||
project_id = self.shares_client.tenant_id
|
||||
|
||||
# Create private share type
|
||||
st_create = self.create_share_type(
|
||||
name, False, extra_specs=extra_specs)
|
||||
self.assertEqual(name, st_create['share_type']['name'])
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# It should not be listed without access
|
||||
st_list = self.shares_v2_client.list_share_types()
|
||||
sts = st_list["share_types"]
|
||||
self.assertFalse(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - none expected
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
self.assertEmpty(access)
|
||||
|
||||
# Add project access to share type
|
||||
access = self.shares_v2_client.add_access_to_share_type(
|
||||
st_id, project_id)
|
||||
|
||||
# Now it should be listed
|
||||
st_list = self.shares_client.list_share_types()
|
||||
sts = st_list["share_types"]
|
||||
self.assertTrue(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - one expected
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
expected = [{'share_type_id': st_id, 'project_id': project_id}, ]
|
||||
self.assertEqual(expected, access)
|
||||
|
||||
# Remove project access from share type
|
||||
access = self.shares_v2_client.remove_access_from_share_type(
|
||||
st_id, project_id)
|
||||
|
||||
# It should not be listed without access
|
||||
st_list = self.shares_client.list_share_types()
|
||||
sts = st_list["share_types"]
|
||||
self.assertFalse(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - none expected
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
self.assertEmpty(access)
|
@ -1,132 +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 copy
|
||||
|
||||
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
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
class ExtraSpecsReadAdminTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ExtraSpecsReadAdminTest, cls).resource_setup()
|
||||
cls.share_type_name = data_utils.rand_name("share-type")
|
||||
cls.required_extra_specs = cls.add_extra_specs_to_dict()
|
||||
|
||||
cls.share_type = cls.create_share_type(
|
||||
cls.share_type_name, extra_specs=cls.required_extra_specs)
|
||||
|
||||
cls.st_id = cls.share_type["share_type"]["id"]
|
||||
cls.custom_extra_specs = {"key1": "value1", "key2": "value2"}
|
||||
cls.expected_extra_specs = copy.copy(cls.custom_extra_specs)
|
||||
cls.expected_extra_specs.update(cls.required_extra_specs)
|
||||
|
||||
cls.shares_client.create_share_type_extra_specs(
|
||||
cls.st_id, cls.custom_extra_specs)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_get_one_share_type_extra_spec(self):
|
||||
es_get_one = self.shares_client.get_share_type_extra_spec(
|
||||
self.st_id, "key1")
|
||||
|
||||
self.assertEqual({"key1": self.custom_extra_specs["key1"]}, es_get_one)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_get_all_share_type_extra_specs(self):
|
||||
es_get_all = self.shares_client.get_share_type_extra_specs(self.st_id)
|
||||
|
||||
self.assertEqual(self.expected_extra_specs, es_get_all)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ExtraSpecsWriteAdminTest(base.BaseSharesAdminTest):
|
||||
|
||||
def setUp(self):
|
||||
super(ExtraSpecsWriteAdminTest, self).setUp()
|
||||
self.required_extra_specs = self.add_extra_specs_to_dict()
|
||||
self.custom_extra_specs = {"key1": "value1", "key2": "value2"}
|
||||
self.share_type_name = data_utils.rand_name("share-type")
|
||||
|
||||
# Create share type
|
||||
self.share_type = self.create_share_type(
|
||||
self.share_type_name, extra_specs=self.required_extra_specs)
|
||||
|
||||
self.st_id = self.share_type['share_type']['id']
|
||||
|
||||
# Create extra specs for share type
|
||||
self.shares_client.create_share_type_extra_specs(
|
||||
self.st_id, self.custom_extra_specs)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_one_share_type_extra_spec(self):
|
||||
self.custom_extra_specs["key1"] = "fake_value1_updated"
|
||||
|
||||
# Update extra specs of share type
|
||||
update_one = self.shares_client.update_share_type_extra_spec(
|
||||
self.st_id, "key1", self.custom_extra_specs["key1"])
|
||||
self.assertEqual({"key1": self.custom_extra_specs["key1"]}, update_one)
|
||||
|
||||
get = self.shares_client.get_share_type_extra_specs(self.st_id)
|
||||
expected_extra_specs = self.custom_extra_specs
|
||||
expected_extra_specs.update(self.required_extra_specs)
|
||||
self.assertEqual(self.custom_extra_specs, get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_all_share_type_extra_specs(self):
|
||||
self.custom_extra_specs["key2"] = "value2_updated"
|
||||
|
||||
# Update extra specs of share type
|
||||
update_all = self.shares_client.update_share_type_extra_specs(
|
||||
self.st_id, self.custom_extra_specs)
|
||||
self.assertEqual(self.custom_extra_specs, update_all)
|
||||
|
||||
get = self.shares_client.get_share_type_extra_specs(self.st_id)
|
||||
expected_extra_specs = self.custom_extra_specs
|
||||
expected_extra_specs.update(self.required_extra_specs)
|
||||
self.assertEqual(self.custom_extra_specs, get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_delete_one_share_type_extra_spec(self):
|
||||
# Delete one extra spec for share type
|
||||
self.shares_client.delete_share_type_extra_spec(self.st_id, "key1")
|
||||
|
||||
# Get metadata
|
||||
get = self.shares_client.get_share_type_extra_specs(self.st_id)
|
||||
|
||||
self.assertNotIn('key1', get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data(*set(['2.24', LATEST_MICROVERSION]))
|
||||
def test_delete_snapshot_support_extra_spec(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
# Delete one extra spec for share type
|
||||
self.shares_v2_client.delete_share_type_extra_spec(
|
||||
self.st_id, 'snapshot_support', version=version)
|
||||
|
||||
# Get metadata
|
||||
share_type_extra_specs = self.shares_client.get_share_type_extra_specs(
|
||||
self.st_id)
|
||||
|
||||
self.assertNotIn('snapshot_support', share_type_extra_specs)
|
@ -1,311 +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 ddt
|
||||
from tempest import config
|
||||
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.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ExtraSpecsAdminNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
def _create_share_type(self):
|
||||
name = data_utils.rand_name("unique_st_name")
|
||||
extra_specs = self.add_extra_specs_to_dict({"key": "value"})
|
||||
return self.create_share_type(
|
||||
name, extra_specs=extra_specs, client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_extra_specs_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.create_share_type_extra_specs,
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({"key": "new_value"}))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_extra_specs_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.get_share_type_extra_specs,
|
||||
st["share_type"]["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_spec_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.get_share_type_extra_spec,
|
||||
st["share_type"]["id"], "key")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_specs_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.get_share_type_extra_specs,
|
||||
st["share_type"]["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_read_extra_specs_on_share_type_with_user(self):
|
||||
st = self._create_share_type()
|
||||
share_type = self.shares_v2_client.get_share_type(
|
||||
st['share_type']['id'])
|
||||
# Verify a non-admin can only read the required extra-specs
|
||||
expected_keys = ['driver_handles_share_servers', 'snapshot_support']
|
||||
if utils.is_microversion_ge(CONF.share.max_api_microversion, '2.24'):
|
||||
expected_keys.append('create_share_from_snapshot_support')
|
||||
if utils.is_microversion_ge(CONF.share.max_api_microversion,
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION):
|
||||
expected_keys.append('revert_to_snapshot_support')
|
||||
if utils.is_microversion_ge(CONF.share.max_api_microversion, '2.32'):
|
||||
expected_keys.append('mount_snapshot_support')
|
||||
actual_keys = share_type['share_type']['extra_specs'].keys()
|
||||
self.assertEqual(sorted(expected_keys), sorted(actual_keys),
|
||||
'Incorrect extra specs visible to non-admin user; '
|
||||
'expected %s, got %s' % (expected_keys, actual_keys))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_extra_spec_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.update_share_type_extra_spec,
|
||||
st["share_type"]["id"], "key", "new_value")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_extra_specs_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.update_share_type_extra_specs,
|
||||
st["share_type"]["id"], {"key": "new_value"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_extra_specs_with_user(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.delete_share_type_extra_spec,
|
||||
st["share_type"]["id"], "key")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_set_too_long_key(self):
|
||||
too_big_key = "k" * 256
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({too_big_key: "value"}))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_set_too_long_value_with_creation(self):
|
||||
too_big_value = "v" * 256
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({"key": too_big_value}))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_set_too_long_value_with_update(self):
|
||||
too_big_value = "v" * 256
|
||||
st = self._create_share_type()
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs(
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({"key": "value"}))
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.update_share_type_extra_specs,
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({"key": too_big_value}))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_set_too_long_value_with_update_of_one_key(self):
|
||||
too_big_value = "v" * 256
|
||||
st = self._create_share_type()
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs(
|
||||
st["share_type"]["id"],
|
||||
self.add_extra_specs_to_dict({"key": "value"}))
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.update_share_type_extra_spec,
|
||||
st["share_type"]["id"], "key", too_big_value)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_es_with_empty_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_specs, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_es_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_specs,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_es_with_empty_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
"", {"key1": "value1", })
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_es_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
data_utils.rand_name("fake"), {"key1": "value1", })
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_es_with_empty_specs(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
st["share_type"]["id"], "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_es_with_invalid_specs(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.create_share_type_extra_specs,
|
||||
st["share_type"]["id"], {"": "value_with_empty_key"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_spec_with_empty_key(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_spec,
|
||||
st["share_type"]["id"], "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_spec_with_invalid_key(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_spec,
|
||||
st["share_type"]["id"], data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_specs_with_empty_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_specs,
|
||||
"")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_extra_specs_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type_extra_specs,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_es_key_with_empty_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.delete_share_type_extra_spec,
|
||||
"", "key", )
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_es_key_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.delete_share_type_extra_spec,
|
||||
data_utils.rand_name("fake"), "key", )
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_with_invalid_key(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.delete_share_type_extra_spec,
|
||||
st["share_type"]["id"], data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_spec_with_empty_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.update_share_type_extra_spec,
|
||||
"", "key", "new_value")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_spec_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.update_share_type_extra_spec,
|
||||
data_utils.rand_name("fake"), "key", "new_value")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_spec_with_empty_key(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.update_share_type_extra_spec,
|
||||
st["share_type"]["id"], "", "new_value")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_with_invalid_shr_type_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.update_share_type_extra_specs,
|
||||
data_utils.rand_name("fake"), {"key": "new_value"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_with_invalid_specs(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.update_share_type_extra_specs,
|
||||
st["share_type"]["id"], {"": "new_value"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_spec_driver_handles_share_servers(self):
|
||||
st = self._create_share_type()
|
||||
|
||||
# Try delete extra spec 'driver_handles_share_servers'
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.admin_shares_v2_client.delete_share_type_extra_spec,
|
||||
st["share_type"]["id"],
|
||||
"driver_handles_share_servers")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@ddt.data('2.0', '2.23')
|
||||
def test_try_delete_required_spec_snapshot_support_version(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
st = self._create_share_type()
|
||||
# Try delete extra spec 'snapshot_support'
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.admin_shares_v2_client.delete_share_type_extra_spec,
|
||||
st["share_type"]["id"], "snapshot_support", version=version)
|
@ -1,116 +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 ddt
|
||||
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
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareTypesAdminNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
def _create_share_type(self):
|
||||
name = data_utils.rand_name("unique_st_name")
|
||||
extra_specs = self.add_extra_specs_to_dict({"key": "value"})
|
||||
return self.create_share_type(
|
||||
name, extra_specs=extra_specs, client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_nonexistent_share_type(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.create_share,
|
||||
share_type_id=data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_type_with_empty_name(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_type, '',
|
||||
client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_type_with_too_big_name(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_share_type,
|
||||
"x" * 256,
|
||||
client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@ddt.data('2.0', '2.6', '2.40')
|
||||
def test_create_share_type_with_description_in_wrong_version(
|
||||
self, version):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_share_type,
|
||||
data_utils.rand_name("tempest_type_name"),
|
||||
extra_specs=self.add_extra_specs_to_dict(),
|
||||
description="tempest_type_description",
|
||||
version=version,
|
||||
client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_share_type_by_nonexistent_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_type,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_share_type_by_nonexistent_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.delete_share_type,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_duplicate_of_share_type(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.create_share_type,
|
||||
st["share_type"]["name"],
|
||||
extra_specs=self.add_extra_specs_to_dict(),
|
||||
client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_share_type_allowed_for_public(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.admin_shares_v2_client.add_access_to_share_type,
|
||||
st["share_type"]["id"],
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_remove_share_type_allowed_for_public(self):
|
||||
st = self._create_share_type()
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.admin_shares_v2_client.remove_access_from_share_type,
|
||||
st["share_type"]["id"],
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_share_type_by_nonexistent_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.add_access_to_share_type,
|
||||
data_utils.rand_name("fake"),
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_remove_share_type_by_nonexistent_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.remove_access_from_share_type,
|
||||
data_utils.rand_name("fake"),
|
||||
self.admin_shares_v2_client.tenant_id)
|
@ -1,405 +0,0 @@
|
||||
# Copyright 2014 Mirantis Inc. All Rights Reserved.
|
||||
# Copyright (c) 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.
|
||||
|
||||
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.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesActionsAdminTest(base.BaseSharesAdminTest):
|
||||
"""Covers share functionality, that doesn't related to share type."""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesActionsAdminTest, cls).resource_setup()
|
||||
|
||||
cls.shares = []
|
||||
|
||||
# create share type for share filtering purposes
|
||||
cls.st_name = data_utils.rand_name("tempest-st-name")
|
||||
cls.extra_specs = cls.add_extra_specs_to_dict(
|
||||
{'storage_protocol': CONF.share.capability_storage_protocol})
|
||||
cls.st = cls.create_share_type(
|
||||
name=cls.st_name,
|
||||
cleanup_in_class=True,
|
||||
extra_specs=cls.extra_specs,
|
||||
)
|
||||
|
||||
# create share
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.metadata = {
|
||||
'foo_key_share_1': 'foo_value_share_1',
|
||||
'bar_key_share_1': 'foo_value_share_1',
|
||||
}
|
||||
cls.shares.append(cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
metadata=cls.metadata,
|
||||
share_type_id=cls.st['share_type']['id'],
|
||||
))
|
||||
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
|
||||
cls.snap_desc = data_utils.rand_name(
|
||||
"tempest-snapshot-description")
|
||||
cls.snap = cls.create_snapshot_wait_for_active(
|
||||
cls.shares[0]["id"], cls.snap_name, cls.snap_desc)
|
||||
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
|
||||
# create second share from snapshot for purposes of sorting and
|
||||
# snapshot filtering
|
||||
cls.share_name2 = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc2 = data_utils.rand_name(
|
||||
"tempest-share-description")
|
||||
cls.metadata2 = {
|
||||
'foo_key_share_2': 'foo_value_share_2',
|
||||
'bar_key_share_2': 'foo_value_share_2',
|
||||
}
|
||||
cls.shares.append(cls.create_share(
|
||||
name=cls.share_name2,
|
||||
description=cls.share_desc2,
|
||||
metadata=cls.metadata2,
|
||||
snapshot_id=cls.snap['id'],
|
||||
))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share(self):
|
||||
|
||||
# get share
|
||||
share = self.shares_client.get_share(self.shares[0]['id'])
|
||||
|
||||
# verify keys
|
||||
expected_keys = ["status", "description", "links", "availability_zone",
|
||||
"created_at", "export_location", "share_proto",
|
||||
"name", "snapshot_id", "id", "size"]
|
||||
actual_keys = share.keys()
|
||||
[self.assertIn(key, actual_keys) for key in expected_keys]
|
||||
|
||||
# verify values
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (self.share_name,
|
||||
share["name"])
|
||||
self.assertEqual(self.share_name, str(share["name"]), msg)
|
||||
|
||||
msg = ("Expected description: '%s', "
|
||||
"actual description: '%s'" % (self.share_desc,
|
||||
share["description"]))
|
||||
self.assertEqual(self.share_desc, str(share["description"]), msg)
|
||||
|
||||
msg = "Expected size: '%s', actual size: '%s'" % (
|
||||
CONF.share.share_size, share["size"])
|
||||
self.assertEqual(CONF.share.share_size, int(share["size"]), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares(self):
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares()
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id", "links"]
|
||||
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
for share in self.shares:
|
||||
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail(self):
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail()
|
||||
|
||||
# verify keys
|
||||
keys = [
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "export_location", "share_proto", "host",
|
||||
"name", "snapshot_id", "id", "size", "project_id",
|
||||
]
|
||||
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
|
||||
|
||||
# our shares in list and have no duplicates
|
||||
for share in self.shares:
|
||||
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_metadata(self):
|
||||
filters = {'metadata': self.metadata}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertDictContainsSubset(
|
||||
filters['metadata'], share['metadata'])
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_extra_specs(self):
|
||||
filters = {
|
||||
"extra_specs": {
|
||||
"storage_protocol": CONF.share.capability_storage_protocol,
|
||||
}
|
||||
}
|
||||
share_type_list = self.shares_client.list_share_types()["share_types"]
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
shares_ids = [s["id"] for s in shares]
|
||||
for share in self.shares:
|
||||
self.assertIn(share["id"], shares_ids)
|
||||
for share in shares:
|
||||
# find its name or id, get id
|
||||
st_id = None
|
||||
for st in share_type_list:
|
||||
if share["share_type"] in (st["id"], st["name"]):
|
||||
st_id = st["id"]
|
||||
break
|
||||
if st_id is None:
|
||||
raise ValueError(
|
||||
"Share '%(s_id)s' listed with extra_specs filter has "
|
||||
"nonexistent share type '%(st)s'." % {
|
||||
"s_id": share["id"], "st": share["share_type"]}
|
||||
)
|
||||
extra_specs = self.shares_client.get_share_type_extra_specs(st_id)
|
||||
self.assertDictContainsSubset(filters["extra_specs"], extra_specs)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_share_type_id(self):
|
||||
filters = {'share_type_id': self.st['share_type']['id']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
st_list = self.shares_client.list_share_types()
|
||||
# find its name or id, get id
|
||||
sts = st_list["share_types"]
|
||||
st_id = None
|
||||
for st in sts:
|
||||
if share["share_type"] in [st["id"], st["name"]]:
|
||||
st_id = st["id"]
|
||||
break
|
||||
if st_id is None:
|
||||
raise ValueError(
|
||||
"Share '%(s_id)s' listed with share_type_id filter has "
|
||||
"nonexistent share type '%(st)s'." % {
|
||||
"s_id": share["id"], "st": share["share_type"]}
|
||||
)
|
||||
self.assertEqual(
|
||||
filters['share_type_id'], st_id)
|
||||
share_ids = [share['id'] for share in shares]
|
||||
for share in self.shares:
|
||||
self.assertIn(share['id'], share_ids)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_host(self):
|
||||
base_share = self.shares_client.get_share(self.shares[0]['id'])
|
||||
filters = {'host': base_share['host']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(filters['host'], share['host'])
|
||||
|
||||
@base.skip_if_microversion_lt("2.35")
|
||||
@ddt.data(('path', True), ('id', True), ('path', False), ('id', False))
|
||||
@ddt.unpack
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_or_with_detail_filter_by_export_location(
|
||||
self, export_location_type, enable_detail):
|
||||
export_locations = self.shares_v2_client.list_share_export_locations(
|
||||
self.shares[0]['id'])
|
||||
if not isinstance(export_locations, (list, tuple, set)):
|
||||
export_locations = (export_locations, )
|
||||
|
||||
filters = {
|
||||
'export_location_' + export_location_type:
|
||||
export_locations[0][export_location_type],
|
||||
}
|
||||
# list shares
|
||||
if enable_detail:
|
||||
shares = self.shares_v2_client.list_shares_with_detail(
|
||||
params=filters)
|
||||
else:
|
||||
shares = self.shares_v2_client.list_shares(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertEqual(1, len(shares))
|
||||
self.assertEqual(self.shares[0]['id'], shares[0]['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_list_shares_with_detail_filter_by_share_network_id(self):
|
||||
base_share = self.shares_client.get_share(self.shares[0]['id'])
|
||||
filters = {'share_network_id': base_share['share_network_id']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(
|
||||
filters['share_network_id'], share['share_network_id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_list_shares_with_detail_filter_by_snapshot_id(self):
|
||||
filters = {'snapshot_id': self.snap['id']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(filters['snapshot_id'], share['snapshot_id'])
|
||||
self.assertFalse(self.shares[0]['id'] in [s['id'] for s in shares])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_with_asc_sorting(self):
|
||||
filters = {'sort_key': 'created_at', 'sort_dir': 'asc'}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
sorted_list = [share['created_at'] for share in shares]
|
||||
self.assertEqual(sorted(sorted_list), sorted_list)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_existed_name(self):
|
||||
# list shares by name, at least one share is expected
|
||||
params = {"name": self.share_name}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(self.share_name, shares[0]["name"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_fake_name(self):
|
||||
# list shares by fake name, no shares are expected
|
||||
params = {"name": data_utils.rand_name("fake-nonexistent-name")}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_active_status(self):
|
||||
# list shares by active status, at least one share is expected
|
||||
params = {"status": "available"}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(params["status"], share["status"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_fake_status(self):
|
||||
# list shares by fake status, no shares are expected
|
||||
params = {"status": 'fake'}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_get_snapshot(self):
|
||||
|
||||
# get snapshot
|
||||
get = self.shares_client.get_snapshot(self.snap["id"])
|
||||
|
||||
# verify keys
|
||||
expected_keys = ["status", "links", "share_id", "name",
|
||||
"share_proto", "created_at",
|
||||
"description", "id", "share_size"]
|
||||
actual_keys = get.keys()
|
||||
[self.assertIn(key, actual_keys) for key in expected_keys]
|
||||
|
||||
# verify data
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (self.snap_name,
|
||||
get["name"])
|
||||
self.assertEqual(self.snap_name, get["name"], msg)
|
||||
|
||||
msg = ("Expected description: '%s', "
|
||||
"actual description: '%s'" % (self.snap_desc,
|
||||
get["description"]))
|
||||
self.assertEqual(self.snap_desc, get["description"], msg)
|
||||
|
||||
msg = ("Expected share_id: '%s', "
|
||||
"actual share_id: '%s'" % (self.shares[0]["id"],
|
||||
get["share_id"]))
|
||||
self.assertEqual(self.shares[0]["id"], get["share_id"], msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots(self):
|
||||
|
||||
# list share snapshots
|
||||
snaps = self.shares_client.list_snapshots()
|
||||
|
||||
# verify keys
|
||||
keys = ["id", "name", "links"]
|
||||
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots_with_detail(self):
|
||||
|
||||
# list share snapshots
|
||||
snaps = self.shares_client.list_snapshots_with_detail()
|
||||
|
||||
# verify keys
|
||||
keys = ["status", "links", "share_id", "name",
|
||||
"share_proto", "created_at",
|
||||
"description", "id", "share_size"]
|
||||
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
@ -1,140 +0,0 @@
|
||||
# Copyright (c) 2017 Hitachi Data Systems, 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 uuidutils
|
||||
import six
|
||||
from tempest import config
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests and
|
||||
CONF.share.run_snapshot_tests,
|
||||
"Mountable snapshots tests are disabled.")
|
||||
@ddt.ddt
|
||||
class SnapshotExportLocationsTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(SnapshotExportLocationsTest, cls).setup_clients()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SnapshotExportLocationsTest, cls).resource_setup()
|
||||
cls.share = cls.create_share(client=cls.admin_client)
|
||||
cls.snapshot = cls.create_snapshot_wait_for_active(
|
||||
cls.share['id'], client=cls.admin_client)
|
||||
cls.snapshot = cls.admin_client.get_snapshot(cls.snapshot['id'])
|
||||
cls.snapshot_instances = cls.admin_client.list_snapshot_instances(
|
||||
snapshot_id=cls.snapshot['id'])
|
||||
|
||||
def _verify_export_location_structure(
|
||||
self, export_locations, role='admin', detail=False):
|
||||
|
||||
# Determine which keys to expect based on role, version and format
|
||||
summary_keys = ['id', 'path', 'links']
|
||||
if detail:
|
||||
summary_keys.extend(['created_at', 'updated_at'])
|
||||
|
||||
admin_summary_keys = summary_keys + [
|
||||
'share_snapshot_instance_id', 'is_admin_only']
|
||||
|
||||
if role == 'admin':
|
||||
expected_keys = admin_summary_keys
|
||||
else:
|
||||
expected_keys = summary_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 role == 'admin':
|
||||
self.assertIn(export_location['is_admin_only'], (True, False))
|
||||
self.assertTrue(uuidutils.is_uuid_like(
|
||||
export_location['share_snapshot_instance_id']))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_snapshot_export_location(self):
|
||||
export_locations = (
|
||||
self.admin_client.list_snapshot_export_locations(
|
||||
self.snapshot['id']))
|
||||
|
||||
for el in export_locations:
|
||||
self._verify_export_location_structure(el)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_snapshot_export_location(self):
|
||||
export_locations = (
|
||||
self.admin_client.list_snapshot_export_locations(
|
||||
self.snapshot['id']))
|
||||
|
||||
for export_location in export_locations:
|
||||
el = self.admin_client.get_snapshot_export_location(
|
||||
self.snapshot['id'], export_location['id'])
|
||||
self._verify_export_location_structure(el, detail=True)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_snapshot_instance_export_location(self):
|
||||
for snapshot_instance in self.snapshot_instances:
|
||||
export_locations = (
|
||||
self.admin_client.list_snapshot_instance_export_locations(
|
||||
snapshot_instance['id']))
|
||||
for el in export_locations:
|
||||
el = self.admin_client.get_snapshot_instance_export_location(
|
||||
snapshot_instance['id'], el['id'])
|
||||
self._verify_export_location_structure(el, detail=True)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_snapshot_contains_all_export_locations_of_all_snapshot_instances(
|
||||
self):
|
||||
snapshot_export_locations = (
|
||||
self.admin_client.list_snapshot_export_locations(
|
||||
self.snapshot['id']))
|
||||
snapshot_instances_export_locations = []
|
||||
for snapshot_instance in self.snapshot_instances:
|
||||
snapshot_instance_export_locations = (
|
||||
self.admin_client.list_snapshot_instance_export_locations(
|
||||
snapshot_instance['id']))
|
||||
snapshot_instances_export_locations.extend(
|
||||
snapshot_instance_export_locations)
|
||||
|
||||
self.assertEqual(
|
||||
len(snapshot_export_locations),
|
||||
len(snapshot_instances_export_locations)
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(snapshot_export_locations, key=lambda el: el['id']),
|
||||
sorted(snapshot_instances_export_locations,
|
||||
key=lambda el: el['id'])
|
||||
)
|
@ -1,140 +0,0 @@
|
||||
# Copyright (c) 2017 Hitachi Data Systems, 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
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests and
|
||||
CONF.share.run_snapshot_tests,
|
||||
"Mountable snapshots tests are disabled.")
|
||||
class SnapshotExportLocationsNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(SnapshotExportLocationsNegativeTest, cls).setup_clients()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
cls.isolated_client = cls.alt_shares_v2_client
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SnapshotExportLocationsNegativeTest, cls).resource_setup()
|
||||
cls.share = cls.create_share(client=cls.admin_client)
|
||||
cls.snapshot = cls.create_snapshot_wait_for_active(
|
||||
cls.share['id'], client=cls.admin_client)
|
||||
cls.snapshot = cls.admin_client.get_snapshot(cls.snapshot['id'])
|
||||
cls.snapshot_instances = cls.admin_client.list_snapshot_instances(
|
||||
snapshot_id=cls.snapshot['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_inexistent_snapshot_export_location(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_client.get_snapshot_export_location,
|
||||
self.snapshot['id'],
|
||||
"fake-inexistent-snapshot-export-location-id",
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_snapshot_export_locations_by_member(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.isolated_client.list_snapshot_export_locations,
|
||||
self.snapshot['id']
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_snapshot_export_location_by_member(self):
|
||||
export_locations = (
|
||||
self.admin_client.list_snapshot_export_locations(
|
||||
self.snapshot['id']))
|
||||
|
||||
for export_location in export_locations:
|
||||
if export_location['is_admin_only']:
|
||||
continue
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.isolated_client.get_snapshot_export_location,
|
||||
self.snapshot['id'],
|
||||
export_location['id']
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_inexistent_snapshot_instance_export_location(self):
|
||||
for snapshot_instance in self.snapshot_instances:
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_client.get_snapshot_instance_export_location,
|
||||
snapshot_instance['id'],
|
||||
"fake-inexistent-snapshot-export-location-id",
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_snapshot_instance_export_location_by_member(self):
|
||||
for snapshot_instance in self.snapshot_instances:
|
||||
export_locations = (
|
||||
self.admin_client.list_snapshot_instance_export_locations(
|
||||
snapshot_instance['id']))
|
||||
for el in export_locations:
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.isolated_client.get_snapshot_instance_export_location,
|
||||
snapshot_instance['id'], el['id'],
|
||||
)
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests and
|
||||
CONF.share.run_snapshot_tests,
|
||||
"Mountable snapshots tests are disabled.")
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
class SnapshotExportLocationsAPIOnlyNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(SnapshotExportLocationsAPIOnlyNegativeTest, cls).setup_clients()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
cls.isolated_client = cls.alt_shares_v2_client
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_export_locations_by_nonexistent_snapshot(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_client.list_snapshot_export_locations,
|
||||
"fake-inexistent-snapshot-id",
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_export_locations_by_nonexistent_snapshot_instance(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_client.list_snapshot_instance_export_locations,
|
||||
"fake-inexistent-snapshot-instance-id",
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_inexistent_snapshot_instance_export_locations_by_member(
|
||||
self):
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.isolated_client.list_snapshot_instance_export_locations,
|
||||
"fake-inexistent-snapshot-instance-id"
|
||||
)
|
@ -1,170 +0,0 @@
|
||||
# Copyright 2015 EMC Corporation.
|
||||
# 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
|
||||
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
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
|
||||
protocol = 'nfs'
|
||||
|
||||
# NOTE(vponomaryov): be careful running these tests using generic driver
|
||||
# because cinder volume snapshots won't be deleted.
|
||||
|
||||
@classmethod
|
||||
@base.skip_if_microversion_lt("2.12")
|
||||
@testtools.skipIf(
|
||||
CONF.share.multitenancy_enabled,
|
||||
"Only for driver_handles_share_servers = False driver mode.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_manage_unmanage_snapshot_tests,
|
||||
"Manage/unmanage snapshot tests are disabled.")
|
||||
def resource_setup(cls):
|
||||
super(ManageNFSSnapshotTest, 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 type
|
||||
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
||||
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.st = cls.create_share_type(
|
||||
name=cls.st_name,
|
||||
cleanup_in_class=True,
|
||||
extra_specs=cls.extra_specs)
|
||||
|
||||
# Create the base share
|
||||
cls.share = cls.create_share(share_type_id=cls.st['share_type']['id'],
|
||||
share_protocol=cls.protocol)
|
||||
|
||||
# Get updated data
|
||||
cls.share = cls.shares_v2_client.get_share(cls.share['id'])
|
||||
|
||||
def _test_manage(self, snapshot, version=CONF.share.max_api_microversion):
|
||||
name = ("Name for 'managed' snapshot that had ID %s" %
|
||||
snapshot['id'])
|
||||
description = "Description for 'managed' snapshot"
|
||||
|
||||
# Manage snapshot
|
||||
share_id = snapshot['share_id']
|
||||
snapshot = self.shares_v2_client.manage_snapshot(
|
||||
share_id,
|
||||
snapshot['provider_location'],
|
||||
name=name,
|
||||
description=description,
|
||||
# Some drivers require additional parameters passed as driver
|
||||
# options, as follows:
|
||||
# - size: Hitachi HNAS Driver
|
||||
driver_options={'size': snapshot['size']},
|
||||
version=version,
|
||||
)
|
||||
|
||||
# Add managed snapshot to cleanup queue
|
||||
self.method_resources.insert(
|
||||
0, {'type': 'snapshot', 'id': snapshot['id'],
|
||||
'client': self.shares_v2_client})
|
||||
|
||||
# Wait for success
|
||||
self.shares_v2_client.wait_for_snapshot_status(snapshot['id'],
|
||||
'available')
|
||||
|
||||
# Verify manage snapshot API response
|
||||
expected_keys = ["status", "links", "share_id", "name",
|
||||
"share_proto", "created_at",
|
||||
"description", "id", "share_size", "size",
|
||||
"provider_location"]
|
||||
if utils.is_microversion_ge(version, '2.17'):
|
||||
expected_keys.extend(["user_id", "project_id"])
|
||||
|
||||
actual_keys = snapshot.keys()
|
||||
|
||||
# Strict key check
|
||||
self.assertEqual(set(expected_keys), set(actual_keys))
|
||||
|
||||
# Verify data of managed snapshot
|
||||
get_snapshot = self.shares_v2_client.get_snapshot(snapshot['id'])
|
||||
self.assertEqual(name, get_snapshot['name'])
|
||||
self.assertEqual(description, get_snapshot['description'])
|
||||
self.assertEqual(snapshot['share_id'], get_snapshot['share_id'])
|
||||
|
||||
# Delete snapshot
|
||||
self.shares_v2_client.delete_snapshot(get_snapshot['id'])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
snapshot_id=get_snapshot['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_snapshot,
|
||||
get_snapshot['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data('2.12', '2.16', CONF.share.max_api_microversion)
|
||||
def test_manage_different_versions(self, version):
|
||||
"""Run snapshot manage test for multiple versions.
|
||||
|
||||
This test is configured with ddt to run for the configured maximum
|
||||
version as well as versions 2.12 (when the API was introduced) and
|
||||
2.16.
|
||||
"""
|
||||
# Skip in case specified version is not supported
|
||||
utils.skip_if_microversion_not_supported(version)
|
||||
|
||||
snap_name = data_utils.rand_name("tempest-snapshot-name")
|
||||
snap_desc = data_utils.rand_name("tempest-snapshot-description")
|
||||
# Create snapshot
|
||||
snapshot = self.create_snapshot_wait_for_active(
|
||||
self.share['id'], snap_name, snap_desc)
|
||||
snapshot = self.shares_v2_client.get_snapshot(snapshot['id'])
|
||||
# Unmanage snapshot
|
||||
self.shares_v2_client.unmanage_snapshot(snapshot['id'],
|
||||
version=version)
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
snapshot_id=snapshot['id'])
|
||||
|
||||
# Manage snapshot
|
||||
self._test_manage(snapshot=snapshot, version=version)
|
||||
|
||||
|
||||
class ManageCIFSSnapshotTest(ManageNFSSnapshotTest):
|
||||
protocol = 'cifs'
|
||||
|
||||
|
||||
class ManageGLUSTERFSSnapshotTest(ManageNFSSnapshotTest):
|
||||
protocol = 'glusterfs'
|
||||
|
||||
|
||||
class ManageHDFSSnapshotTest(ManageNFSSnapshotTest):
|
||||
protocol = 'hdfs'
|
||||
|
||||
|
||||
class ManageMapRFSSnapshotTest(ManageNFSSnapshotTest):
|
||||
protocol = 'maprfs'
|
@ -1,115 +0,0 @@
|
||||
# Copyright 2015 EMC Corporation.
|
||||
# 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
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class ManageNFSSnapshotNegativeTest(base.BaseSharesAdminTest):
|
||||
protocol = 'nfs'
|
||||
|
||||
@classmethod
|
||||
@base.skip_if_microversion_lt("2.12")
|
||||
@testtools.skipIf(
|
||||
CONF.share.multitenancy_enabled,
|
||||
"Only for driver_handles_share_servers = False driver mode.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_manage_unmanage_snapshot_tests,
|
||||
"Manage/unmanage snapshot tests are disabled.")
|
||||
def resource_setup(cls):
|
||||
super(ManageNFSSnapshotNegativeTest, 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 type
|
||||
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
||||
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.st = cls.create_share_type(
|
||||
name=cls.st_name,
|
||||
cleanup_in_class=True,
|
||||
extra_specs=cls.extra_specs)
|
||||
|
||||
# Create share
|
||||
cls.share = cls.create_share(
|
||||
share_type_id=cls.st['share_type']['id'],
|
||||
share_protocol=cls.protocol
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_manage_not_found(self):
|
||||
# Manage snapshot fails
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.manage_snapshot,
|
||||
'fake-share-id',
|
||||
'fake-vol-snap-id',
|
||||
driver_options={})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_manage_already_exists(self):
|
||||
# Manage already existing snapshot fails
|
||||
|
||||
# Create snapshot
|
||||
snap = self.create_snapshot_wait_for_active(self.share['id'])
|
||||
get_snap = self.shares_v2_client.get_snapshot(snap['id'])
|
||||
self.assertEqual(self.share['id'], get_snap['share_id'])
|
||||
self.assertIsNotNone(get_snap['provider_location'])
|
||||
|
||||
# Manage snapshot fails
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.shares_v2_client.manage_snapshot,
|
||||
self.share['id'],
|
||||
get_snap['provider_location'],
|
||||
driver_options={})
|
||||
|
||||
# Delete snapshot
|
||||
self.shares_v2_client.delete_snapshot(get_snap['id'])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
snapshot_id=get_snap['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_snapshot,
|
||||
get_snap['id'])
|
||||
|
||||
|
||||
class ManageCIFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
||||
protocol = 'cifs'
|
||||
|
||||
|
||||
class ManageGLUSTERFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
||||
protocol = 'glusterfs'
|
||||
|
||||
|
||||
class ManageHDFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
||||
protocol = 'hdfs'
|
||||
|
||||
|
||||
class ManageMapRFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
||||
protocol = 'maprfs'
|
@ -1,108 +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 oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
MICROVERSION = '2.37'
|
||||
MESSAGE_KEYS = (
|
||||
'created_at',
|
||||
'action_id',
|
||||
'detail_id',
|
||||
'expires_at',
|
||||
'id',
|
||||
'message_level',
|
||||
'request_id',
|
||||
'resource_type',
|
||||
'resource_id',
|
||||
'user_message',
|
||||
'project_id',
|
||||
'links',
|
||||
)
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt(MICROVERSION)
|
||||
class UserMessageTest(base.BaseSharesAdminTest):
|
||||
|
||||
def setUp(self):
|
||||
super(UserMessageTest, self).setUp()
|
||||
self.message = self.create_user_message()
|
||||
|
||||
@decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
|
||||
def test_list_messages(self):
|
||||
body = self.shares_v2_client.list_messages()
|
||||
self.assertIsInstance(body, list)
|
||||
self.assertTrue(self.message['id'], [x['id'] for x in body])
|
||||
message = body[0]
|
||||
self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
|
||||
|
||||
@decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
|
||||
def test_list_messages_sorted_and_paginated(self):
|
||||
self.create_user_message()
|
||||
self.create_user_message()
|
||||
params = {'sort_key': 'resource_id', 'sort_dir': 'asc', 'limit': 2}
|
||||
body = self.shares_v2_client.list_messages(params=params)
|
||||
# tempest/lib/common/rest_client.py's _parse_resp checks
|
||||
# for number of keys in response's dict, if there is only single
|
||||
# key, it returns directly this key, otherwise it returns
|
||||
# parsed body. If limit param is used, then API returns
|
||||
# multiple keys in response ('messages' and 'message_links')
|
||||
messages = body['messages']
|
||||
self.assertIsInstance(messages, list)
|
||||
ids = [x['resource_id'] for x in messages]
|
||||
self.assertEqual(2, len(ids))
|
||||
self.assertEqual(ids, sorted(ids))
|
||||
|
||||
@decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
|
||||
def test_list_messages_filtered(self):
|
||||
self.create_user_message()
|
||||
params = {'resource_id': self.message['resource_id']}
|
||||
body = self.shares_v2_client.list_messages(params=params)
|
||||
self.assertIsInstance(body, list)
|
||||
ids = [x['id'] for x in body]
|
||||
self.assertEqual([self.message['id']], ids)
|
||||
|
||||
@decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
|
||||
def test_show_message(self):
|
||||
self.addCleanup(self.shares_v2_client.delete_message,
|
||||
self.message['id'])
|
||||
|
||||
message = self.shares_v2_client.get_message(self.message['id'])
|
||||
|
||||
self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
|
||||
self.assertTrue(uuidutils.is_uuid_like(message['id']))
|
||||
self.assertEqual('001', message['action_id'])
|
||||
# don't check specific detail_id which may vary
|
||||
# depending on order of filters, we can still check
|
||||
# user_message
|
||||
self.assertIn(
|
||||
'No storage could be allocated for this share request',
|
||||
message['user_message'])
|
||||
self.assertEqual('SHARE', message['resource_type'])
|
||||
self.assertTrue(uuidutils.is_uuid_like(message['resource_id']))
|
||||
self.assertEqual('ERROR', message['message_level'])
|
||||
created_at = timeutils.parse_strtime(message['created_at'])
|
||||
expires_at = timeutils.parse_strtime(message['expires_at'])
|
||||
self.assertGreater(expires_at, created_at)
|
||||
self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
|
||||
|
||||
@decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
|
||||
def test_delete_message(self):
|
||||
self.shares_v2_client.delete_message(self.message['id'])
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
message_id=self.message['id'])
|
@ -1,58 +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 oslo_utils import uuidutils
|
||||
import six
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
MICROVERSION = '2.37'
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt(MICROVERSION)
|
||||
class UserMessageNegativeTest(base.BaseSharesAdminTest):
|
||||
|
||||
def setUp(self):
|
||||
super(UserMessageNegativeTest, self).setUp()
|
||||
self.message = self.create_user_message()
|
||||
|
||||
@decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
|
||||
def test_show_message_of_other_tenants(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt', client_version='2')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
isolated_client.get_message,
|
||||
self.message['id'])
|
||||
|
||||
@decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
|
||||
def test_show_nonexistent_message(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_message,
|
||||
six.text_type(uuidutils.generate_uuid()))
|
||||
|
||||
@decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
|
||||
def test_delete_message_of_other_tenants(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt', client_version='2')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
isolated_client.delete_message,
|
||||
self.message['id'])
|
||||
|
||||
@decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
|
||||
def test_delete_nonexistent_message(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_message,
|
||||
six.text_type(uuidutils.generate_uuid()))
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +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 testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
class AvailabilityZonesTest(base.BaseSharesTest):
|
||||
|
||||
def _list_availability_zones_assertions(self, availability_zones):
|
||||
self.assertGreater(len(availability_zones), 0)
|
||||
keys = ("created_at", "updated_at", "name", "id")
|
||||
for az in availability_zones:
|
||||
self.assertEqual(len(keys), len(az))
|
||||
for key in keys:
|
||||
self.assertIn(key, az)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_availability_zones_legacy_url_api_v1(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
azs = self.shares_client.list_availability_zones()
|
||||
self._list_availability_zones_assertions(azs)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported("2.6")
|
||||
def test_list_availability_zones_legacy_url_api_v2(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
azs = self.shares_v2_client.list_availability_zones(
|
||||
url='os-availability-zone', version='2.6')
|
||||
self._list_availability_zones_assertions(azs)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
def test_list_availability_zones(self):
|
||||
azs = self.shares_v2_client.list_availability_zones(version='2.7')
|
||||
self._list_availability_zones_assertions(azs)
|
@ -1,43 +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.lib import exceptions as lib_exc
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
class AvailabilityZonesNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_availability_zones_api_not_found_with_legacy_url(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.list_availability_zones,
|
||||
url='os-availability-zone',
|
||||
version='2.7',
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_availability_zones_api_not_found(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.list_availability_zones,
|
||||
url='availability-zones',
|
||||
version='2.6',
|
||||
)
|
@ -1,31 +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
|
||||
|
||||
|
||||
class ExtensionsTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_extensions(self):
|
||||
|
||||
# get extensions
|
||||
extensions = self.shares_client.list_extensions()
|
||||
|
||||
# verify response
|
||||
keys = ["alias", "updated", "name", "description"]
|
||||
[self.assertIn(key, ext.keys()) for ext in extensions for key in keys]
|
@ -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
|
||||
|
||||
|
||||
class ShareLimitsTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_limits_keys(self):
|
||||
|
||||
# list limits
|
||||
limits = self.shares_client.get_limits()
|
||||
|
||||
# verify response
|
||||
keys = ["rate", "absolute"]
|
||||
[self.assertIn(key, limits.keys()) for key in keys]
|
||||
|
||||
abs_keys = [
|
||||
"maxTotalShareGigabytes",
|
||||
"maxTotalShares",
|
||||
"maxTotalShareSnapshots",
|
||||
"maxTotalShareNetworks",
|
||||
"maxTotalSnapshotGigabytes",
|
||||
"totalSharesUsed",
|
||||
"totalShareSnapshotsUsed",
|
||||
"totalShareNetworksUsed",
|
||||
"totalShareGigabytesUsed",
|
||||
"totalSnapshotGigabytesUsed",
|
||||
]
|
||||
[self.assertIn(key, limits["absolute"].keys()) for key in abs_keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_limits_values(self):
|
||||
|
||||
# list limits
|
||||
limits = self.shares_client.get_limits()
|
||||
|
||||
# verify integer values for absolute limits
|
||||
abs_l = limits["absolute"]
|
||||
self.assertGreater(int(abs_l["maxTotalShareGigabytes"]), -2)
|
||||
self.assertGreater(int(abs_l["maxTotalShares"]), -2)
|
||||
self.assertGreater(int(abs_l["maxTotalShareSnapshots"]), -2)
|
||||
self.assertGreater(int(abs_l["maxTotalShareNetworks"]), -2)
|
||||
self.assertGreater(int(abs_l["maxTotalSnapshotGigabytes"]), -2)
|
||||
self.assertGreater(int(abs_l["totalSharesUsed"]), -2)
|
||||
self.assertGreater(int(abs_l["totalShareSnapshotsUsed"]), -2)
|
||||
self.assertGreater(int(abs_l["totalShareNetworksUsed"]), -2)
|
||||
self.assertGreater(int(abs_l["totalShareGigabytesUsed"]), -2)
|
||||
self.assertGreater(int(abs_l["totalSnapshotGigabytesUsed"]), -2)
|
@ -1,163 +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
|
||||
|
||||
|
||||
class SharesMetadataTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesMetadataTest, cls).resource_setup()
|
||||
cls.share = cls.create_share()
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_in_share_creation(self):
|
||||
|
||||
md = {u"key1": u"value1", u"key2": u"value2", }
|
||||
|
||||
# create share with metadata
|
||||
share = self.create_share(metadata=md, cleanup_in_class=False)
|
||||
|
||||
# get metadata of share
|
||||
metadata = self.shares_client.get_metadata(share["id"])
|
||||
|
||||
# verify metadata
|
||||
self.assertEqual(md, metadata)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_get_delete_metadata(self):
|
||||
|
||||
md = {u"key3": u"value3", u"key4": u"value4", }
|
||||
|
||||
# create share
|
||||
share = self.create_share(cleanup_in_class=False)
|
||||
|
||||
# set metadata
|
||||
self.shares_client.set_metadata(share["id"], md)
|
||||
|
||||
# read metadata
|
||||
get_md = self.shares_client.get_metadata(share["id"])
|
||||
|
||||
# verify metadata
|
||||
self.assertEqual(md, get_md)
|
||||
|
||||
# delete metadata
|
||||
for key in md.keys():
|
||||
self.shares_client.delete_metadata(share["id"], key)
|
||||
|
||||
# verify deletion of metadata
|
||||
get_metadata = self.shares_client.get_metadata(share["id"])
|
||||
self.assertEqual({}, get_metadata)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_and_update_metadata_by_key(self):
|
||||
|
||||
md1 = {u"key5": u"value5", u"key6": u"value6", }
|
||||
md2 = {u"key7": u"value7", u"key8": u"value8", }
|
||||
|
||||
# create share
|
||||
share = self.create_share(cleanup_in_class=False)
|
||||
|
||||
# set metadata
|
||||
self.shares_client.set_metadata(share["id"], md1)
|
||||
|
||||
# update metadata
|
||||
self.shares_client.update_all_metadata(share["id"], md2)
|
||||
|
||||
# get metadata
|
||||
get_md = self.shares_client.get_metadata(share["id"])
|
||||
|
||||
# verify metadata
|
||||
self.assertEqual(md2, get_md)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_min_size_key(self):
|
||||
data = {"k": "value"}
|
||||
|
||||
self.shares_client.set_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data['k'], body_get.get('k'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_max_size_key(self):
|
||||
max_key = "k" * 255
|
||||
data = {max_key: "value"}
|
||||
|
||||
self.shares_client.set_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertIn(max_key, body_get)
|
||||
self.assertEqual(data[max_key], body_get.get(max_key))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_min_size_value(self):
|
||||
data = {"key": "v"}
|
||||
|
||||
self.shares_client.set_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data['key'], body_get['key'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_max_size_value(self):
|
||||
max_value = "v" * 1023
|
||||
data = {"key": max_value}
|
||||
|
||||
self.shares_client.set_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data['key'], body_get['key'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_upd_metadata_min_size_key(self):
|
||||
data = {"k": "value"}
|
||||
|
||||
self.shares_client.update_all_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data, body_get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_upd_metadata_max_size_key(self):
|
||||
max_key = "k" * 255
|
||||
data = {max_key: "value"}
|
||||
|
||||
self.shares_client.update_all_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data, body_get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_upd_metadata_min_size_value(self):
|
||||
data = {"key": "v"}
|
||||
|
||||
self.shares_client.update_all_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data, body_get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_upd_metadata_max_size_value(self):
|
||||
max_value = "v" * 1023
|
||||
data = {"key": max_value}
|
||||
|
||||
self.shares_client.update_all_metadata(self.share["id"], data)
|
||||
|
||||
body_get = self.shares_client.get_metadata(self.share["id"])
|
||||
self.assertEqual(data, body_get)
|
@ -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 SharesMetadataAPIOnlyNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@ddt.data(True, False)
|
||||
def test_try_set_metadata_to_unexisting_share(self, is_v2_client):
|
||||
md = {u"key1": u"value1", u"key2": u"value2", }
|
||||
client = self.shares_v2_client if is_v2_client else self.shares_client
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
client.set_metadata,
|
||||
"wrong_share_id", md)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@ddt.data(True, False)
|
||||
def test_try_update_all_metadata_for_unexisting_share(self, is_v2_client):
|
||||
md = {u"key1": u"value1", u"key2": u"value2", }
|
||||
client = self.shares_v2_client if is_v2_client else self.shares_client
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
client.update_all_metadata,
|
||||
"wrong_share_id", md)
|
||||
|
||||
|
||||
class SharesMetadataNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesMetadataNegativeTest, cls).resource_setup()
|
||||
cls.share = cls.create_share()
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_set_metadata_with_empty_key(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.set_metadata,
|
||||
self.share["id"], {"": "value"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_upd_metadata_with_empty_key(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.update_all_metadata,
|
||||
self.share["id"], {"": "value"})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_set_metadata_with_too_big_key(self):
|
||||
too_big_key = "x" * 256
|
||||
md = {too_big_key: "value"}
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.set_metadata,
|
||||
self.share["id"], md)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_upd_metadata_with_too_big_key(self):
|
||||
too_big_key = "x" * 256
|
||||
md = {too_big_key: "value"}
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.update_all_metadata,
|
||||
self.share["id"], md)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_set_metadata_with_too_big_value(self):
|
||||
too_big_value = "x" * 1024
|
||||
md = {"key": too_big_value}
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.set_metadata,
|
||||
self.share["id"], md)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_upd_metadata_with_too_big_value(self):
|
||||
too_big_value = "x" * 1024
|
||||
md = {"key": too_big_value}
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.update_all_metadata,
|
||||
self.share["id"], md)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_delete_unexisting_metadata(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_metadata,
|
||||
self.share["id"], "wrong_key")
|
@ -1,172 +0,0 @@
|
||||
# Copyright 2015 Goutham Pacha Ravi
|
||||
# Copyright 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.
|
||||
|
||||
from tempest import config
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
API_MICROVERSIONS_HEADER_LOWER = 'x-openstack-manila-api-version'
|
||||
API_MICROVERSIONS_HEADER = 'X-OpenStack-Manila-API-Version'
|
||||
_MIN_API_VERSION = CONF.share.min_api_microversion
|
||||
_MAX_API_VERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
class MicroversionsTest(base.BaseSharesTest):
|
||||
"""Request and validate REST API Microversions.
|
||||
|
||||
Sends HTTP GET requests to the version API to validate microversions.
|
||||
"""
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_root_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request()
|
||||
|
||||
self.assertEqual(300, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v1.0', 'v2.0'}, set(ids))
|
||||
|
||||
self.assertNotIn(API_MICROVERSIONS_HEADER_LOWER, resp)
|
||||
self.assertNotIn('vary', resp)
|
||||
|
||||
v1 = [v for v in version_list if v['id'] == 'v1.0'][0]
|
||||
self.assertEqual('', v1.get('min_version'))
|
||||
self.assertEqual('', v1.get('version'))
|
||||
|
||||
v2 = [v for v in version_list if v['id'] == 'v2.0'][0]
|
||||
self.assertEqual(_MIN_API_VERSION, v2.get('min_version'))
|
||||
self.assertEqual(_MAX_API_VERSION, v2.get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v1_no_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v1')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v1.0'}, set(ids))
|
||||
|
||||
self.assertEqual('1.0', resp.get(API_MICROVERSIONS_HEADER_LOWER))
|
||||
self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
|
||||
self.assertEqual('', version_list[0].get('min_version'))
|
||||
self.assertEqual('', version_list[0].get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v1_with_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v1', version='5.0')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v1.0'}, set(ids))
|
||||
|
||||
self.assertEqual('1.0', resp.get(API_MICROVERSIONS_HEADER_LOWER))
|
||||
self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
|
||||
self.assertEqual('', version_list[0].get('min_version'))
|
||||
self.assertEqual('', version_list[0].get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v2_no_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v2.0'}, set(ids))
|
||||
|
||||
self.assertEqual(_MIN_API_VERSION,
|
||||
resp.get(API_MICROVERSIONS_HEADER_LOWER))
|
||||
self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
|
||||
self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
|
||||
self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v2_min_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2', version=_MIN_API_VERSION)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v2.0'}, set(ids))
|
||||
|
||||
self.assertEqual(_MIN_API_VERSION,
|
||||
resp.get(API_MICROVERSIONS_HEADER_LOWER))
|
||||
self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
|
||||
self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
|
||||
self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v2_max_version(self):
|
||||
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2', version=_MAX_API_VERSION)
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
ids = [v['id'] for v in version_list]
|
||||
self.assertEqual({'v2.0'}, set(ids))
|
||||
|
||||
self.assertEqual(_MAX_API_VERSION,
|
||||
resp.get(API_MICROVERSIONS_HEADER_LOWER))
|
||||
self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
|
||||
self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
|
||||
self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v2_invalid_version(self):
|
||||
|
||||
resp, _ = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2', version='1.2.1')
|
||||
|
||||
self.assertEqual(400, resp.status)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_microversions_v2_unacceptable_version(self):
|
||||
|
||||
# First get max version from the server
|
||||
resp, resp_body = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2')
|
||||
|
||||
self.assertEqual(200, resp.status)
|
||||
|
||||
version_list = resp_body['versions']
|
||||
latest_version = version_list[0].get('version')
|
||||
major, minor = [int(ver) for ver in latest_version.split(".")]
|
||||
next_version = ('%s.%s' % (major + 1, minor + 1))
|
||||
|
||||
# Request a version that is too high
|
||||
resp, _ = self.shares_v2_client.send_microversion_request(
|
||||
script_name='v2', version=next_version)
|
||||
|
||||
self.assertEqual(406, resp.status)
|
@ -1,88 +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
|
||||
import itertools
|
||||
from tempest import config
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesQuotasTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
if not CONF.share.run_quota_tests:
|
||||
msg = "Quota tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
super(SharesQuotasTest, cls).resource_setup()
|
||||
cls.user_id = cls.shares_v2_client.user_id or cls.user_id
|
||||
cls.tenant_id = cls.shares_v2_client.tenant_id or cls.tenant_id
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_default_quotas(self, client_name):
|
||||
quotas = getattr(self, client_name).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)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_show_quotas(self, client_name):
|
||||
quotas = getattr(self, client_name).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)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_show_quotas_for_user(self, client_name):
|
||||
quotas = getattr(self, client_name).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)
|
||||
|
||||
@ddt.data(
|
||||
*itertools.product(set(("2.25", CONF.share.max_api_microversion)),
|
||||
(True, False))
|
||||
)
|
||||
@ddt.unpack
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported("2.25")
|
||||
def test_show_quotas_detail(self, microversion, with_user):
|
||||
quota_args = {"tenant_id": self.tenant_id, "version": microversion, }
|
||||
if with_user:
|
||||
quota_args.update({"user_id": self.user_id})
|
||||
quotas = self.shares_v2_client.detail_quotas(**quota_args)
|
||||
quota_keys = list(quotas.keys())
|
||||
for outer in ('gigabytes', 'snapshot_gigabytes', 'shares',
|
||||
'snapshots', 'share_networks'):
|
||||
self.assertIn(outer, quota_keys)
|
||||
outer_keys = list(quotas[outer].keys())
|
||||
for inner in ('in_use', 'limit', 'reserved'):
|
||||
self.assertIn(inner, outer_keys)
|
||||
self.assertGreater(int(quotas[outer][inner]), -2)
|
@ -1,60 +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
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesQuotasNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
if not CONF.share.run_quota_tests:
|
||||
msg = "Quota tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
super(SharesQuotasNegativeTest, cls).resource_setup()
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_quotas_with_empty_tenant_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.show_quotas, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_reset_quotas_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_v2_client.reset_quotas,
|
||||
self.shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_quotas_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_v2_client.update_quotas,
|
||||
self.shares_v2_client.tenant_id,
|
||||
shares=9)
|
||||
|
||||
@ddt.data("2.6", "2.7", "2.24")
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_quotas_detail_with_wrong_version(self, microversion):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.detail_quotas,
|
||||
self.shares_v2_client.tenant_id,
|
||||
version=microversion)
|
@ -1,406 +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'
|
||||
SUMMARY_KEYS = ['share_id', 'id', 'replica_state', 'status']
|
||||
DETAIL_KEYS = SUMMARY_KEYS + ['availability_zone', 'updated_at',
|
||||
'share_network_id', 'created_at']
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_replication_tests,
|
||||
'Replication tests are disabled.')
|
||||
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
|
||||
class ReplicationTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ReplicationTest, cls).resource_setup()
|
||||
# Create share_type
|
||||
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
|
||||
cls.admin_client = cls.admin_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.creation_data = {'kwargs': {
|
||||
'share_type_id': cls.share_type['id'],
|
||||
'availability_zone': cls.share_zone,
|
||||
}}
|
||||
|
||||
# Data for creating shares in parallel
|
||||
data = [cls.creation_data, cls.creation_data]
|
||||
cls.shares = cls.create_shares(data)
|
||||
cls.shares = [cls.shares_v2_client.get_share(s['id']) for s in
|
||||
cls.shares]
|
||||
cls.instance_id1 = cls._get_instance(cls.shares[0])
|
||||
cls.instance_id2 = cls._get_instance(cls.shares[1])
|
||||
|
||||
@classmethod
|
||||
def _get_instance(cls, share):
|
||||
share_instances = cls.admin_client.get_instances_of_share(share["id"])
|
||||
return share_instances[0]["id"]
|
||||
|
||||
def _verify_create_replica(self):
|
||||
# Create the replica
|
||||
share_replica = self.create_share_replica(self.shares[0]["id"],
|
||||
self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
share_replicas = self.shares_v2_client.list_share_replicas(
|
||||
share_id=self.shares[0]["id"])
|
||||
# Ensure replica is created successfully.
|
||||
replica_ids = [replica["id"] for replica in share_replicas]
|
||||
self.assertIn(share_replica["id"], replica_ids)
|
||||
return share_replica
|
||||
|
||||
def _verify_active_replica_count(self, share_id):
|
||||
# List replicas
|
||||
replica_list = self.shares_v2_client.list_share_replicas(
|
||||
share_id=share_id)
|
||||
|
||||
# Check if there is only 1 'active' replica before promotion.
|
||||
active_replicas = self._filter_replica_list(
|
||||
replica_list, constants.REPLICATION_STATE_ACTIVE)
|
||||
self.assertEqual(1, len(active_replicas))
|
||||
|
||||
def _filter_replica_list(self, replica_list, r_state):
|
||||
# Iterate through replica list to filter based on replica_state
|
||||
return [replica for replica in replica_list
|
||||
if replica['replica_state'] == r_state]
|
||||
|
||||
def _verify_in_sync_replica_promotion(self, share, original_replica):
|
||||
# Verify that 'in-sync' replica has been promoted successfully
|
||||
|
||||
# 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)
|
||||
# Wait for replica state to update after creation
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
# Promote the first in_sync replica to active state
|
||||
promoted_replica = self.promote_share_replica(replica['id'])
|
||||
# Delete the demoted replica so promoted replica can be cleaned
|
||||
# during the cleanup of the share.
|
||||
self.addCleanup(self.delete_share_replica, original_replica['id'])
|
||||
self._verify_active_replica_count(share["id"])
|
||||
# Verify the replica_state for promoted replica
|
||||
promoted_replica = self.shares_v2_client.get_share_replica(
|
||||
promoted_replica["id"])
|
||||
self.assertEqual(constants.REPLICATION_STATE_ACTIVE,
|
||||
promoted_replica["replica_state"])
|
||||
|
||||
def _check_skip_promotion_tests(self):
|
||||
# Check if the replication type is right for replica promotion tests
|
||||
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))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_add_delete_share_replica(self):
|
||||
# Create the replica
|
||||
share_replica = self._verify_create_replica()
|
||||
|
||||
# Delete the replica
|
||||
self.delete_share_replica(share_replica["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_add_access_rule_create_replica_delete_rule(self):
|
||||
# Add access rule to the share
|
||||
access_type, access_to = self._get_access_rule_data_from_config()
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.shares[0]["id"], access_type, access_to, 'ro')
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.shares[0]["id"], rule["id"], constants.RULE_STATE_ACTIVE)
|
||||
|
||||
# Create the replica
|
||||
self._verify_create_replica()
|
||||
|
||||
# Verify access_rules_status transitions to 'active' state.
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.shares[0]["id"], constants.RULE_STATE_ACTIVE,
|
||||
status_attr='access_rules_status')
|
||||
|
||||
# Delete rule and wait for deletion
|
||||
self.shares_v2_client.delete_access_rule(self.shares[0]["id"],
|
||||
rule["id"])
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.shares[0]['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_replica_add_access_rule_delete_replica(self):
|
||||
access_type, access_to = self._get_access_rule_data_from_config()
|
||||
# Create the replica
|
||||
share_replica = self._verify_create_replica()
|
||||
|
||||
# Add access rule
|
||||
self.shares_v2_client.create_access_rule(
|
||||
self.shares[0]["id"], access_type, access_to, 'ro')
|
||||
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.shares[0]["id"], constants.RULE_STATE_ACTIVE,
|
||||
status_attr='access_rules_status')
|
||||
|
||||
# Delete the replica
|
||||
self.delete_share_replica(share_replica["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_multiple_share_replicas_tests,
|
||||
'Multiple share replicas tests are disabled.')
|
||||
def test_add_multiple_share_replicas(self):
|
||||
rep_domain, pools = self.get_pools_for_replication_domain()
|
||||
if len(pools) < 3:
|
||||
msg = ("Replication domain %(domain)s has only %(count)s pools. "
|
||||
"Need at least 3 pools to run this test." %
|
||||
{"domain": rep_domain, "count": len(pools)})
|
||||
raise self.skipException(msg)
|
||||
# Add the replicas
|
||||
share_replica1 = self.create_share_replica(self.shares[0]["id"],
|
||||
self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
share_replica2 = self.create_share_replica(self.shares[0]["id"],
|
||||
self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
self.shares_v2_client.get_share_replica(share_replica2['id'])
|
||||
|
||||
share_replicas = self.admin_client.list_share_replicas(
|
||||
share_id=self.shares[0]["id"])
|
||||
replica_host_set = {r['host'] for r in share_replicas}
|
||||
|
||||
# Assert that replicas are created on different pools.
|
||||
msg = "More than one replica is created on the same pool."
|
||||
self.assertEqual(3, len(replica_host_set), msg)
|
||||
# Verify replicas are in the replica list
|
||||
replica_ids = [replica["id"] for replica in share_replicas]
|
||||
self.assertIn(share_replica1["id"], replica_ids)
|
||||
self.assertIn(share_replica2["id"], replica_ids)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_promote_in_sync_share_replica(self):
|
||||
# Test promote 'in_sync' share_replica to 'active' state
|
||||
self._check_skip_promotion_tests()
|
||||
share = self.create_shares([self.creation_data])[0]
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
share["id"])[0]
|
||||
self._verify_in_sync_replica_promotion(share, original_replica)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_add_rule_promote_share_replica_verify_rule(self):
|
||||
# Verify the access rule stays intact after share replica promotion
|
||||
self._check_skip_promotion_tests()
|
||||
|
||||
share = self.create_shares([self.creation_data])[0]
|
||||
# Add access rule
|
||||
access_type, access_to = self._get_access_rule_data_from_config()
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
share["id"], access_type, access_to, 'ro')
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
share["id"], rule["id"], constants.RULE_STATE_ACTIVE)
|
||||
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
share["id"])[0]
|
||||
self._verify_in_sync_replica_promotion(share, original_replica)
|
||||
|
||||
# verify rule's values
|
||||
rules_list = self.shares_v2_client.list_access_rules(share["id"])
|
||||
self.assertEqual(1, len(rules_list))
|
||||
self.assertEqual(access_type, rules_list[0]["access_type"])
|
||||
self.assertEqual(access_to, rules_list[0]["access_to"])
|
||||
self.assertEqual('ro', rules_list[0]["access_level"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_promote_and_promote_back(self):
|
||||
# Test promote back and forth between 2 share replicas
|
||||
self._check_skip_promotion_tests()
|
||||
|
||||
# Create a new share
|
||||
share = self.create_shares([self.creation_data])[0]
|
||||
|
||||
# Discover the original replica
|
||||
initial_replicas = self.shares_v2_client.list_share_replicas(
|
||||
share_id=share['id'])
|
||||
self.assertEqual(1, len(initial_replicas),
|
||||
'%s replicas initially created for share %s' %
|
||||
(len(initial_replicas), share['id']))
|
||||
original_replica = initial_replicas[0]
|
||||
|
||||
# Create a new replica
|
||||
new_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
new_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
# Promote the new replica to active and verify the replica states
|
||||
self.promote_share_replica(new_replica['id'])
|
||||
self._verify_active_replica_count(share["id"])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
original_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
# Promote the original replica back to active
|
||||
self.promote_share_replica(original_replica['id'])
|
||||
self._verify_active_replica_count(share["id"])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
new_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_active_replication_state(self):
|
||||
# Verify the replica_state of first instance is set to active.
|
||||
replica = self.shares_v2_client.get_share_replica(self.instance_id1)
|
||||
self.assertEqual(
|
||||
constants.REPLICATION_STATE_ACTIVE, replica['replica_state'])
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_replication_tests,
|
||||
'Replication tests are disabled.')
|
||||
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
|
||||
class ReplicationActionsTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ReplicationActionsTest, cls).resource_setup()
|
||||
# Create share_type
|
||||
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
|
||||
cls.admin_client = cls.admin_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.creation_data = {'kwargs': {
|
||||
'share_type_id': cls.share_type['id'],
|
||||
'availability_zone': cls.share_zone,
|
||||
}}
|
||||
|
||||
# Data for creating shares in parallel
|
||||
data = [cls.creation_data, cls.creation_data]
|
||||
cls.shares = cls.create_shares(data)
|
||||
cls.shares = [cls.shares_v2_client.get_share(s['id']) for s in
|
||||
cls.shares]
|
||||
cls.instance_id1 = cls._get_instance(cls.shares[0])
|
||||
cls.instance_id2 = cls._get_instance(cls.shares[1])
|
||||
|
||||
# Create replicas to 2 shares
|
||||
cls.replica1 = cls.create_share_replica(cls.shares[0]["id"],
|
||||
cls.replica_zone,
|
||||
cleanup_in_class=True)
|
||||
cls.replica2 = cls.create_share_replica(cls.shares[1]["id"],
|
||||
cls.replica_zone,
|
||||
cleanup_in_class=True)
|
||||
|
||||
@classmethod
|
||||
def _get_instance(cls, share):
|
||||
share_instances = cls.admin_client.get_instances_of_share(share["id"])
|
||||
return share_instances[0]["id"]
|
||||
|
||||
def _validate_replica_list(self, replica_list, detail=True):
|
||||
# Verify keys
|
||||
if detail:
|
||||
keys = DETAIL_KEYS
|
||||
else:
|
||||
keys = SUMMARY_KEYS
|
||||
for replica in replica_list:
|
||||
self.assertEqual(sorted(keys), sorted(replica.keys()))
|
||||
# Check for duplicates
|
||||
replica_id_list = [sr["id"] for sr in replica_list
|
||||
if sr["id"] == replica["id"]]
|
||||
msg = "Replica %s appears %s times in replica list." % (
|
||||
replica['id'], len(replica_id_list))
|
||||
self.assertEqual(1, len(replica_id_list), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_show_share_replica(self):
|
||||
replica = self.shares_v2_client.get_share_replica(self.replica1["id"])
|
||||
|
||||
actual_keys = sorted(list(replica.keys()))
|
||||
detail_keys = sorted(DETAIL_KEYS)
|
||||
self.assertEqual(detail_keys, actual_keys,
|
||||
'Share Replica %s has incorrect keys; '
|
||||
'expected %s, got %s.' % (replica["id"],
|
||||
detail_keys, actual_keys))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_detail_list_share_replicas_for_share(self):
|
||||
# List replicas for share
|
||||
replica_list = self.shares_v2_client.list_share_replicas(
|
||||
share_id=self.shares[0]["id"])
|
||||
replica_ids_list = [rep['id'] for rep in replica_list]
|
||||
self.assertIn(self.replica1['id'], replica_ids_list,
|
||||
'Replica %s was not returned in the list of replicas: %s'
|
||||
% (self.replica1['id'], replica_list))
|
||||
# Verify keys
|
||||
self._validate_replica_list(replica_list)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_detail_list_share_replicas_for_all_shares(self):
|
||||
# List replicas for all available shares
|
||||
replica_list = self.shares_v2_client.list_share_replicas()
|
||||
replica_ids_list = [rep['id'] for rep in replica_list]
|
||||
for replica in [self.replica1, self.replica2]:
|
||||
self.assertIn(replica['id'], replica_ids_list,
|
||||
'Replica %s was not returned in the list of '
|
||||
'replicas: %s' % (replica['id'], replica_list))
|
||||
# Verify keys
|
||||
self._validate_replica_list(replica_list)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_summary_list_share_replicas_for_all_shares(self):
|
||||
# List replicas
|
||||
replica_list = self.shares_v2_client.list_share_replicas_summary()
|
||||
|
||||
# Verify keys
|
||||
self._validate_replica_list(replica_list, detail=False)
|
@ -1,215 +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
|
||||
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.')
|
||||
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
|
||||
class ReplicationNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ReplicationNegativeTest, cls).resource_setup()
|
||||
# Create share_type
|
||||
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
|
||||
cls.admin_client = cls.admin_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.share1, cls.instance_id1 = cls._create_share_get_instance()
|
||||
|
||||
@classmethod
|
||||
def _create_share_get_instance(cls):
|
||||
share = cls.create_share(share_type_id=cls.share_type["id"],
|
||||
availability_zone=cls.share_zone,)
|
||||
share_instances = cls.admin_client.get_instances_of_share(
|
||||
share["id"], version=_MIN_SUPPORTED_MICROVERSION
|
||||
)
|
||||
instance_id = share_instances[0]["id"]
|
||||
return share, instance_id
|
||||
|
||||
def _is_replication_type_promotable(self):
|
||||
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))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_add_replica_to_share_with_no_replication_share_type(self):
|
||||
# Create share without replication type
|
||||
share_type = self.create_share_type(
|
||||
data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX),
|
||||
extra_specs=self.add_extra_specs_to_dict(),
|
||||
client=self.admin_client)["share_type"]
|
||||
share = self.create_share(share_type_id=share_type["id"])
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_share_replica,
|
||||
share['id'],
|
||||
self.replica_zone)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_add_replica_to_share_with_error_state(self):
|
||||
# Set "error" state
|
||||
self.admin_client.reset_state(
|
||||
self.share1['id'], constants.STATUS_ERROR)
|
||||
self.addCleanup(self.admin_client.reset_state,
|
||||
self.share1['id'],
|
||||
constants.STATUS_AVAILABLE)
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_share_replica,
|
||||
self.share1['id'],
|
||||
self.replica_zone)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_delete_last_active_replica(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.delete_share_replica,
|
||||
self.instance_id1)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_try_delete_share_having_replica(self):
|
||||
self.create_share_replica(self.share1["id"], self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_share,
|
||||
self.share1["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_promote_out_of_sync_share_replica(self):
|
||||
# Test promoting an out_of_sync share_replica to active state
|
||||
self._is_replication_type_promotable()
|
||||
share, instance_id = self._create_share_get_instance()
|
||||
replica = self.create_share_replica(share["id"], self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
# Set replica state to out of sync
|
||||
self.admin_client.reset_share_replica_state(
|
||||
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC)
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
replica['id'], constants.REPLICATION_STATE_OUT_OF_SYNC,
|
||||
status_attr='replica_state')
|
||||
# Try promoting the first out_of_sync replica to active state
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_v2_client.promote_share_replica,
|
||||
replica['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_promote_active_share_replica(self):
|
||||
# Test promote active share_replica
|
||||
self._is_replication_type_promotable()
|
||||
|
||||
# Try promoting the active replica
|
||||
self.shares_v2_client.promote_share_replica(self.instance_id1,
|
||||
expected_status=200)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_promote_share_replica_for_writable_share_type(self):
|
||||
# Test promote active share_replica for writable share
|
||||
if self.replication_type != "writable":
|
||||
raise self.skipException("Option backend_replication_type "
|
||||
"should be writable!")
|
||||
share, instance_id = self._create_share_get_instance()
|
||||
replica = self.create_share_replica(share["id"], self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
# By default, 'writable' replica is expected to be in active state
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
replica["id"], constants.REPLICATION_STATE_ACTIVE,
|
||||
status_attr='replica_state')
|
||||
|
||||
# Try promoting the replica
|
||||
self.shares_v2_client.promote_share_replica(replica['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_add_access_rule_share_replica_error_status(self):
|
||||
access_type, access_to = self._get_access_rule_data_from_config()
|
||||
# Create the replica
|
||||
share_replica = self.create_share_replica(self.share1["id"],
|
||||
self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
# Reset the replica status to error
|
||||
self.admin_client.reset_share_replica_status(
|
||||
share_replica['id'], constants.STATUS_ERROR)
|
||||
|
||||
# Verify access rule cannot be added
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.admin_client.create_access_rule,
|
||||
self.share1["id"], access_type, access_to, 'ro')
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_host_assisted_migration_tests or
|
||||
CONF.share.run_driver_assisted_migration_tests,
|
||||
"Share migration tests are disabled.")
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.29")
|
||||
def test_migration_of_replicated_share(self):
|
||||
pools = self.admin_client.list_pools(detail=True)['pools']
|
||||
hosts = [p['name'] for p in pools]
|
||||
self.create_share_replica(self.share1["id"], self.replica_zone,
|
||||
cleanup_in_class=False)
|
||||
share_host = self.admin_client.get_share(self.share1['id'])['host']
|
||||
|
||||
for host in hosts:
|
||||
if host != share_host:
|
||||
dest_host = host
|
||||
break
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict, self.admin_client.migrate_share,
|
||||
self.share1['id'], dest_host)
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_replication_tests,
|
||||
'Replication tests are disabled.')
|
||||
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
|
||||
class ReplicationAPIOnlyNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_replica_by_nonexistent_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_replica,
|
||||
data_utils.rand_uuid())
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_replica_by_nonexistent_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_share_replica,
|
||||
data_utils.rand_uuid())
|
@ -1,218 +0,0 @@
|
||||
# Copyright 2016 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.')
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
'Snapshot tests disabled.')
|
||||
@base.skip_if_microversion_lt(_MIN_SUPPORTED_MICROVERSION)
|
||||
class ReplicationSnapshotTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ReplicationSnapshotTest, cls).resource_setup()
|
||||
# Create share_type
|
||||
name = data_utils.rand_name(constants.TEMPEST_MANILA_PREFIX)
|
||||
cls.admin_client = cls.admin_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.creation_data = {'kwargs': {
|
||||
'share_type_id': cls.share_type['id'],
|
||||
'availability_zone': cls.share_zone,
|
||||
}}
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_snapshot_after_share_replica(self):
|
||||
"""Test the snapshot for replicated share.
|
||||
|
||||
Create replica first and then create a snapshot.
|
||||
Verify that the snapshot is properly created under replica by
|
||||
creating a share from that snapshot.
|
||||
"""
|
||||
share = self.create_share(share_type_id=self.share_type['id'],
|
||||
availability_zone=self.share_zone)
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
share["id"])[0]
|
||||
|
||||
share_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone,
|
||||
cleanup=False)
|
||||
self.addCleanup(self.delete_share_replica, original_replica['id'])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
snapshot = self.create_snapshot_wait_for_active(share["id"])
|
||||
self.promote_share_replica(share_replica['id'])
|
||||
self.delete_share_replica(original_replica['id'])
|
||||
|
||||
snapshot = self.shares_v2_client.get_snapshot(snapshot['id'])
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, snapshot['status'])
|
||||
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
self.create_share(snapshot_id=snapshot['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_snapshot_before_share_replica(self):
|
||||
"""Test the snapshot for replicated share.
|
||||
|
||||
Create snapshot before creating share replica for the same
|
||||
share.
|
||||
Verify snapshot by creating share from the snapshot.
|
||||
"""
|
||||
share = self.create_share(share_type_id=self.share_type['id'],
|
||||
availability_zone=self.share_zone)
|
||||
snapshot = self.create_snapshot_wait_for_active(share["id"])
|
||||
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
share["id"])[0]
|
||||
share_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone,
|
||||
cleanup=False)
|
||||
self.addCleanup(self.delete_share_replica, original_replica['id'])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
# Wait for snapshot1 to become available
|
||||
self.shares_v2_client.wait_for_snapshot_status(
|
||||
snapshot['id'], "available")
|
||||
|
||||
self.promote_share_replica(share_replica['id'])
|
||||
self.delete_share_replica(original_replica['id'])
|
||||
|
||||
snapshot = self.shares_v2_client.get_snapshot(snapshot['id'])
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, snapshot['status'])
|
||||
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
self.create_share(snapshot_id=snapshot['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_snapshot_before_and_after_share_replica(self):
|
||||
"""Test the snapshot for replicated share.
|
||||
|
||||
Verify that snapshot can be created before and after share replica
|
||||
being created.
|
||||
Verify snapshots by creating share from the snapshots.
|
||||
"""
|
||||
share = self.create_share(share_type_id=self.share_type['id'],
|
||||
availability_zone=self.share_zone)
|
||||
snapshot1 = self.create_snapshot_wait_for_active(share["id"])
|
||||
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
share["id"])[0]
|
||||
|
||||
share_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone,
|
||||
cleanup=False)
|
||||
self.addCleanup(self.delete_share_replica, original_replica['id'])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
snapshot2 = self.create_snapshot_wait_for_active(share["id"])
|
||||
|
||||
# Wait for snapshot1 to become available
|
||||
self.shares_v2_client.wait_for_snapshot_status(
|
||||
snapshot1['id'], "available")
|
||||
|
||||
self.promote_share_replica(share_replica['id'])
|
||||
# Remove the original active replica to ensure that snapshot is
|
||||
# still being created successfully.
|
||||
self.delete_share_replica(original_replica['id'])
|
||||
|
||||
snapshot1 = self.shares_v2_client.get_snapshot(snapshot1['id'])
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, snapshot1['status'])
|
||||
|
||||
snapshot2 = self.shares_v2_client.get_snapshot(snapshot2['id'])
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, snapshot2['status'])
|
||||
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
self.create_share(snapshot_id=snapshot1['id'])
|
||||
self.create_share(snapshot_id=snapshot2['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_delete_snapshot_after_adding_replica(self):
|
||||
"""Verify the snapshot delete.
|
||||
|
||||
Ensure that deleting the original snapshot also deletes the
|
||||
snapshot from replica.
|
||||
"""
|
||||
|
||||
share = self.create_share(share_type_id=self.share_type['id'],
|
||||
availability_zone=self.share_zone)
|
||||
share_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone)
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
snapshot = self.create_snapshot_wait_for_active(share["id"])
|
||||
self.shares_v2_client.delete_snapshot(snapshot['id'])
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
snapshot_id=snapshot["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_create_replica_from_snapshot_share(self):
|
||||
"""Test replica for a share that was created from snapshot."""
|
||||
|
||||
share = self.create_share(share_type_id=self.share_type['id'],
|
||||
availability_zone=self.share_zone)
|
||||
orig_snapshot = self.create_snapshot_wait_for_active(share["id"])
|
||||
snap_share = self.create_share(snapshot_id=orig_snapshot['id'])
|
||||
original_replica = self.shares_v2_client.list_share_replicas(
|
||||
snap_share["id"])[0]
|
||||
share_replica = self.create_share_replica(snap_share["id"],
|
||||
self.replica_zone,
|
||||
cleanup=False)
|
||||
self.addCleanup(self.delete_share_replica, original_replica['id'])
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
self.promote_share_replica(share_replica['id'])
|
||||
# Delete the demoted replica so promoted replica can be cleaned
|
||||
# during the cleanup
|
||||
self.delete_share_replica(original_replica['id'])
|
@ -1,161 +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
|
||||
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
|
||||
|
||||
|
||||
@base.skip_if_microversion_not_supported(
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
@ddt.ddt
|
||||
class RevertToSnapshotTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(RevertToSnapshotTest, cls).skip_checks()
|
||||
if not CONF.share.run_revert_to_snapshot_tests:
|
||||
msg = "Revert to snapshot tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
if not CONF.share.capability_snapshot_support:
|
||||
msg = "Snapshot support is disabled."
|
||||
raise cls.skipException(msg)
|
||||
if not CONF.share.run_snapshot_tests:
|
||||
msg = "Snapshot tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(RevertToSnapshotTest, cls).resource_setup()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
pools = cls.admin_client.list_pools(detail=True)['pools']
|
||||
revert_support = [
|
||||
pool['capabilities'][constants.REVERT_TO_SNAPSHOT_SUPPORT]
|
||||
for pool in pools]
|
||||
if not any(revert_support):
|
||||
msg = "Revert to snapshot not supported."
|
||||
raise cls.skipException(msg)
|
||||
|
||||
cls.share_type_name = data_utils.rand_name("share-type")
|
||||
extra_specs = {constants.REVERT_TO_SNAPSHOT_SUPPORT: True}
|
||||
cls.revert_enabled_extra_specs = cls.add_extra_specs_to_dict(
|
||||
extra_specs=extra_specs)
|
||||
|
||||
cls.share_type = cls.create_share_type(
|
||||
cls.share_type_name,
|
||||
extra_specs=cls.revert_enabled_extra_specs,
|
||||
client=cls.admin_client)
|
||||
|
||||
cls.st_id = cls.share_type['share_type']['id']
|
||||
|
||||
cls.share = cls.create_share(share_type_id=cls.st_id)
|
||||
|
||||
if CONF.share.run_replication_tests:
|
||||
# Create replicated share type
|
||||
cls.replicated_share_type_name = data_utils.rand_name("share-type")
|
||||
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]
|
||||
|
||||
extra_specs = cls.add_extra_specs_to_dict({
|
||||
"replication_type": cls.replication_type,
|
||||
constants.REVERT_TO_SNAPSHOT_SUPPORT: True,
|
||||
})
|
||||
share_type = cls.create_share_type(
|
||||
cls.replicated_share_type_name,
|
||||
extra_specs=extra_specs,
|
||||
client=cls.admin_client)
|
||||
cls.replicated_share_type = share_type["share_type"]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_latest_snapshot(self, version):
|
||||
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
|
||||
cleanup_in_class=False)
|
||||
self.shares_v2_client.revert_to_snapshot(
|
||||
self.share['id'],
|
||||
snapshot['id'],
|
||||
version=version)
|
||||
self.shares_v2_client.wait_for_share_status(self.share['id'],
|
||||
constants.STATUS_AVAILABLE)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_previous_snapshot(self, version):
|
||||
snapshot1 = self.create_snapshot_wait_for_active(
|
||||
self.share['id'], cleanup_in_class=False)
|
||||
snapshot2 = self.create_snapshot_wait_for_active(
|
||||
self.share['id'], cleanup_in_class=False)
|
||||
|
||||
self.shares_v2_client.delete_snapshot(snapshot2['id'])
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
snapshot_id=snapshot2['id'])
|
||||
|
||||
self.shares_v2_client.revert_to_snapshot(self.share['id'],
|
||||
snapshot1['id'],
|
||||
version=version)
|
||||
self.shares_v2_client.wait_for_share_status(self.share['id'],
|
||||
constants.STATUS_AVAILABLE)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@tc.skipUnless(CONF.share.run_replication_tests,
|
||||
'Replication tests are disabled.')
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_replicated_snapshot(self, version):
|
||||
"""Test reverting to a replicated snapshot."""
|
||||
share = self.create_share(
|
||||
share_type_id=self.replicated_share_type['id'],
|
||||
availability_zone=self.share_zone
|
||||
)
|
||||
|
||||
share_replica = self.create_share_replica(share["id"],
|
||||
self.replica_zone)
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
||||
|
||||
snapshot = self.create_snapshot_wait_for_active(share["id"])
|
||||
|
||||
self.shares_v2_client.revert_to_snapshot(
|
||||
share['id'],
|
||||
snapshot['id'],
|
||||
version=version)
|
||||
self.shares_v2_client.wait_for_share_status(share['id'],
|
||||
constants.STATUS_AVAILABLE)
|
||||
self.shares_v2_client.wait_for_share_replica_status(
|
||||
share_replica['id'], constants.REPLICATION_STATE_IN_SYNC,
|
||||
status_attr='replica_state')
|
@ -1,159 +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
|
||||
from tempest.lib import exceptions
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@base.skip_if_microversion_not_supported(
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
@ddt.ddt
|
||||
class RevertToSnapshotNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(RevertToSnapshotNegativeTest, cls).skip_checks()
|
||||
if not CONF.share.run_revert_to_snapshot_tests:
|
||||
msg = "Revert to snapshot tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
if not CONF.share.capability_snapshot_support:
|
||||
msg = "Snapshot support is disabled."
|
||||
raise cls.skipException(msg)
|
||||
if not CONF.share.run_snapshot_tests:
|
||||
msg = "Snapshot tests are disabled."
|
||||
raise cls.skipException(msg)
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(RevertToSnapshotNegativeTest, cls).resource_setup()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
pools = cls.admin_client.list_pools(detail=True)['pools']
|
||||
revert_support = [
|
||||
pool['capabilities'][constants.REVERT_TO_SNAPSHOT_SUPPORT]
|
||||
for pool in pools]
|
||||
if not any(revert_support):
|
||||
msg = "Revert to snapshot not supported."
|
||||
raise cls.skipException(msg)
|
||||
|
||||
cls.share_type_name = data_utils.rand_name("share-type")
|
||||
extra_specs = {constants.REVERT_TO_SNAPSHOT_SUPPORT: True}
|
||||
cls.revert_enabled_extra_specs = cls.add_extra_specs_to_dict(
|
||||
extra_specs=extra_specs)
|
||||
|
||||
cls.share_type = cls.create_share_type(
|
||||
cls.share_type_name,
|
||||
extra_specs=cls.revert_enabled_extra_specs,
|
||||
client=cls.admin_client)
|
||||
|
||||
cls.st_id = cls.share_type['share_type']['id']
|
||||
|
||||
cls.share = cls.create_share(share_type_id=cls.st_id)
|
||||
cls.share2 = cls.create_share(share_type_id=cls.st_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_second_latest_snapshot(self, version):
|
||||
snapshot1 = self.create_snapshot_wait_for_active(
|
||||
self.share['id'], cleanup_in_class=False)
|
||||
self.create_snapshot_wait_for_active(self.share['id'],
|
||||
cleanup_in_class=False)
|
||||
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.revert_to_snapshot,
|
||||
self.share['id'],
|
||||
snapshot1['id'],
|
||||
version=version)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_error_snapshot(self, version):
|
||||
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
|
||||
cleanup_in_class=False)
|
||||
|
||||
self.admin_client.reset_state(snapshot['id'],
|
||||
status=constants.STATUS_ERROR,
|
||||
s_type='snapshots')
|
||||
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.revert_to_snapshot,
|
||||
self.share['id'],
|
||||
snapshot['id'],
|
||||
version=version)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_error_share_to_snapshot(self, version):
|
||||
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
|
||||
cleanup_in_class=False)
|
||||
|
||||
self.admin_client.reset_state(self.share['id'],
|
||||
status=constants.STATUS_ERROR,
|
||||
s_type='shares')
|
||||
|
||||
self.addCleanup(self.admin_client.reset_state,
|
||||
self.share['id'],
|
||||
status=constants.STATUS_AVAILABLE,
|
||||
s_type='shares')
|
||||
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.revert_to_snapshot,
|
||||
self.share['id'],
|
||||
snapshot['id'],
|
||||
version=version)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_missing_snapshot(self, version):
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.shares_v2_client.revert_to_snapshot,
|
||||
self.share['id'],
|
||||
self.share['id'],
|
||||
version=version)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
*{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
|
||||
CONF.share.max_api_microversion}
|
||||
)
|
||||
def test_revert_to_invalid_snapshot(self, version):
|
||||
snapshot = self.create_snapshot_wait_for_active(
|
||||
self.share['id'], cleanup_in_class=False)
|
||||
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.shares_v2_client.revert_to_snapshot,
|
||||
self.share2['id'],
|
||||
snapshot['id'],
|
||||
version=version)
|
@ -1,631 +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
|
||||
import itertools
|
||||
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
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
def _create_delete_ro_access_rule(self, version):
|
||||
"""Common test case for usage in test suites with different decorators.
|
||||
|
||||
:param self: instance of test class
|
||||
"""
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to, 'ro')
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to, 'ro',
|
||||
version=version)
|
||||
|
||||
self.assertEqual('ro', rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after 2.28
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_le(version, '2.9'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
# If the 'access_rules_status' transitions to 'active',
|
||||
# rule state must too
|
||||
rules = self.shares_v2_client.list_access_rules(self.share['id'])
|
||||
rule = [r for r in rules if r['id'] == rule['id']][0]
|
||||
self.assertEqual("active", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareIpRulesForNFSTest(base.BaseSharesTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareIpRulesForNFSTest, cls).resource_setup()
|
||||
if (cls.protocol not in CONF.share.enable_protocols or
|
||||
cls.protocol not in CONF.share.enable_ip_rules_for_protocols):
|
||||
msg = "IP rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.access_type = "ip"
|
||||
cls.access_to = "2.2.2.2"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(*itertools.chain(
|
||||
itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, {4}),
|
||||
itertools.product({'2.38', LATEST_MICROVERSION}, {6})
|
||||
))
|
||||
@ddt.unpack
|
||||
def test_create_delete_access_rules_with_one_ip(self, version,
|
||||
ip_version):
|
||||
|
||||
if ip_version == 4:
|
||||
access_to = utils.rand_ip()
|
||||
else:
|
||||
access_to = utils.rand_ipv6_ip()
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, access_to,
|
||||
version=version)
|
||||
|
||||
self.assertEqual('rw', rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# delete rule and wait for deletion
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(*itertools.chain(
|
||||
itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, {4}),
|
||||
itertools.product({'2.38', LATEST_MICROVERSION}, {6})
|
||||
))
|
||||
@ddt.unpack
|
||||
def test_create_delete_access_rule_with_cidr(self, version, ip_version):
|
||||
if ip_version == 4:
|
||||
access_to = utils.rand_ip(network=True)
|
||||
else:
|
||||
access_to = utils.rand_ipv6_ip(network=True)
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, access_to,
|
||||
version=version)
|
||||
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
self.assertEqual('rw', rule['access_level'])
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# delete rule and wait for deletion
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(
|
||||
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
|
||||
"RO access rule tests are disabled for NFS protocol.")
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_ro_access_rule(self, client_name):
|
||||
_create_delete_ro_access_rule(self, client_name)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareIpRulesForCIFSTest(ShareIpRulesForNFSTest):
|
||||
protocol = "cifs"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(
|
||||
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
|
||||
"RO access rule tests are disabled for CIFS protocol.")
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_ro_access_rule(self, version):
|
||||
_create_delete_ro_access_rule(self, version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareUserRulesForNFSTest(base.BaseSharesTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareUserRulesForNFSTest, cls).resource_setup()
|
||||
if (cls.protocol not in CONF.share.enable_protocols or
|
||||
cls.protocol not in
|
||||
CONF.share.enable_user_rules_for_protocols):
|
||||
msg = "USER rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.access_type = "user"
|
||||
cls.access_to = CONF.share.username_for_user_rules
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_user_rule(self, version):
|
||||
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to,
|
||||
version=version)
|
||||
|
||||
self.assertEqual('rw', rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# delete rule and wait for deletion
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(
|
||||
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
|
||||
"RO access rule tests are disabled for NFS protocol.")
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_ro_access_rule(self, version):
|
||||
_create_delete_ro_access_rule(self, version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareUserRulesForCIFSTest(ShareUserRulesForNFSTest):
|
||||
protocol = "cifs"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(
|
||||
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
|
||||
"RO access rule tests are disabled for CIFS protocol.")
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_ro_access_rule(self, version):
|
||||
_create_delete_ro_access_rule(self, version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareCertRulesForGLUSTERFSTest(base.BaseSharesTest):
|
||||
protocol = "glusterfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareCertRulesForGLUSTERFSTest, cls).resource_setup()
|
||||
if (cls.protocol not in CONF.share.enable_protocols or
|
||||
cls.protocol not in
|
||||
CONF.share.enable_cert_rules_for_protocols):
|
||||
msg = "Cert rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.access_type = "cert"
|
||||
# Provide access to a client identified by a common name (CN) of the
|
||||
# certificate that it possesses.
|
||||
cls.access_to = "client1.com"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_cert_rule(self, version):
|
||||
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to,
|
||||
version=version)
|
||||
|
||||
self.assertEqual('rw', rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# delete rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(
|
||||
"glusterfs" not in CONF.share.enable_ro_access_level_for_protocols,
|
||||
"RO access rule tests are disabled for GLUSTERFS protocol.")
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_create_delete_cert_ro_access_rule(self, version):
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], 'cert', 'client2.com', 'ro')
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], 'cert', 'client2.com', 'ro',
|
||||
version=version)
|
||||
|
||||
self.assertEqual('ro', rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareCephxRulesForCephFSTest(base.BaseSharesTest):
|
||||
protocol = "cephfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareCephxRulesForCephFSTest, cls).resource_setup()
|
||||
if (cls.protocol not in CONF.share.enable_protocols or
|
||||
cls.protocol not in
|
||||
CONF.share.enable_cephx_rules_for_protocols):
|
||||
msg = ("Cephx rule tests for %s protocol are disabled." %
|
||||
cls.protocol)
|
||||
raise cls.skipException(msg)
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.access_type = "cephx"
|
||||
# Provide access to a client identified by a cephx auth id.
|
||||
cls.access_to = "bob"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data(*itertools.product(
|
||||
set(['2.13', '2.27', '2.28', LATEST_MICROVERSION]),
|
||||
("alice", "alice_bob", "alice bob"),
|
||||
('rw', 'ro')))
|
||||
@ddt.unpack
|
||||
def test_create_delete_cephx_rule(self, version, access_to, access_level):
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, access_to, version=version,
|
||||
access_level=access_level)
|
||||
|
||||
self.assertEqual(access_level, rule['access_level'])
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, rule.keys())
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareRulesTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareRulesTest, cls).resource_setup()
|
||||
if not (any(p in CONF.share.enable_ip_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_user_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_cert_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_cephx_rules_for_protocols
|
||||
for p in cls.protocols)):
|
||||
cls.message = "Rule tests are disabled"
|
||||
raise cls.skipException(cls.message)
|
||||
if CONF.share.enable_ip_rules_for_protocols:
|
||||
cls.protocol = CONF.share.enable_ip_rules_for_protocols[0]
|
||||
cls.access_type = "ip"
|
||||
cls.access_to = "8.8.8.8"
|
||||
elif CONF.share.enable_user_rules_for_protocols:
|
||||
cls.protocol = CONF.share.enable_user_rules_for_protocols[0]
|
||||
cls.access_type = "user"
|
||||
cls.access_to = CONF.share.username_for_user_rules
|
||||
elif CONF.share.enable_cert_rules_for_protocols:
|
||||
cls.protocol = CONF.share.enable_cert_rules_for_protocols[0]
|
||||
cls.access_type = "cert"
|
||||
cls.access_to = "client3.com"
|
||||
elif CONF.share.enable_cephx_rules_for_protocols:
|
||||
cls.protocol = CONF.share.enable_cephx_rules_for_protocols[0]
|
||||
cls.access_type = "cephx"
|
||||
cls.access_to = "eve"
|
||||
cls.shares_v2_client.share_protocol = cls.protocol
|
||||
cls.share = cls.create_share()
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_list_access_rules(self, version):
|
||||
if (utils.is_microversion_lt(version, '2.13') and
|
||||
CONF.share.enable_cephx_rules_for_protocols):
|
||||
msg = ("API version %s does not support cephx access type, need "
|
||||
"version >= 2.13." % version)
|
||||
raise self.skipException(msg)
|
||||
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], self.access_type, self.access_to,
|
||||
version=version)
|
||||
|
||||
# verify added rule keys since 2.33 when create rule
|
||||
if utils.is_microversion_ge(version, '2.33'):
|
||||
self.assertIn('created_at', list(rule.keys()))
|
||||
self.assertIn('updated_at', list(rule.keys()))
|
||||
else:
|
||||
self.assertNotIn('created_at', list(rule.keys()))
|
||||
self.assertNotIn('updated_at', list(rule.keys()))
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# list rules
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rules = self.shares_client.list_access_rules(self.share["id"])
|
||||
else:
|
||||
rules = self.shares_v2_client.list_access_rules(self.share["id"],
|
||||
version=version)
|
||||
|
||||
# verify keys
|
||||
keys = ("id", "access_type", "access_to", "access_level")
|
||||
if utils.is_microversion_ge(version, '2.21'):
|
||||
keys += ("access_key", )
|
||||
if utils.is_microversion_ge(version, '2.33'):
|
||||
keys += ("created_at", "updated_at", )
|
||||
for key in keys:
|
||||
[self.assertIn(key, r.keys()) for r in rules]
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
[self.assertNotIn(key, r.keys()) for r in rules]
|
||||
|
||||
# verify values
|
||||
self.assertEqual(self.access_type, rules[0]["access_type"])
|
||||
self.assertEqual(self.access_to, rules[0]["access_to"])
|
||||
self.assertEqual('rw', rules[0]["access_level"])
|
||||
if utils.is_microversion_ge(version, '2.21'):
|
||||
if self.access_type == 'cephx':
|
||||
self.assertIsNotNone(rules[0]['access_key'])
|
||||
else:
|
||||
self.assertIsNone(rules[0]['access_key'])
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
gen = [r["id"] for r in rules if r["id"] in rule["id"]]
|
||||
msg = "expected id lists %s times in rule list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(
|
||||
self.share["id"], rule["id"], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share['id'], version=version)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
|
||||
def test_access_rules_deleted_if_share_deleted(self, version):
|
||||
if (utils.is_microversion_lt(version, '2.13') and
|
||||
CONF.share.enable_cephx_rules_for_protocols):
|
||||
msg = ("API version %s does not support cephx access type, need "
|
||||
"version >= 2.13." % version)
|
||||
raise self.skipException(msg)
|
||||
|
||||
# create share
|
||||
share = self.create_share()
|
||||
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
share["id"], self.access_type, self.access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
share["id"], self.access_type, self.access_to,
|
||||
version=version)
|
||||
|
||||
# rules must start out in 'new' until 2.28 & 'queued_to_apply' after
|
||||
if utils.is_microversion_le(version, "2.27"):
|
||||
self.assertEqual("new", rule['state'])
|
||||
else:
|
||||
self.assertEqual("queued_to_apply", rule['state'])
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# delete share
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_share(share['id'])
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
else:
|
||||
self.shares_v2_client.delete_share(share['id'], version=version)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_id=share['id'], version=version)
|
||||
|
||||
# verify absence of rules for nonexistent share id
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.list_access_rules,
|
||||
share['id'])
|
||||
else:
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.list_access_rules,
|
||||
share['id'], version)
|
@ -1,406 +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.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareIpRulesForNFSNegativeTest(base.BaseSharesMixedTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareIpRulesForNFSNegativeTest, cls).resource_setup()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_ip_rules_for_protocols):
|
||||
msg = "IP rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
# create share
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('1.2.3.256',
|
||||
'1.1.1.-',
|
||||
'1.2.3.4/33',
|
||||
'1.2.3.*',
|
||||
'1.2.3.*/23',
|
||||
'1.2.3.1|23',
|
||||
'1.2.3.1/-1',
|
||||
'1.2.3.1/',
|
||||
'ad80::abaa:0:c2:2/-3',
|
||||
'AD80:ABAA::|26',
|
||||
'2001:DB8:2de:0:0:0:0:e13:200a',
|
||||
)
|
||||
def test_create_access_rule_ip_with_wrong_target(self, ip_address):
|
||||
for client_name in ['shares_client', 'shares_v2_client']:
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "ip", ip_address)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_with_wrong_level(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"],
|
||||
'ip',
|
||||
'2.2.2.2',
|
||||
'su')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('1.0', '2.9', LATEST_MICROVERSION)
|
||||
def test_create_duplicate_of_ip_rule(self, version):
|
||||
# test data
|
||||
access_type = "ip"
|
||||
access_to = "1.2.3.4"
|
||||
|
||||
# create rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
rule = self.shares_client.create_access_rule(
|
||||
self.share["id"], access_type, access_to)
|
||||
else:
|
||||
rule = self.shares_v2_client.create_access_rule(
|
||||
self.share["id"], access_type, access_to, version=version)
|
||||
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
elif utils.is_microversion_eq(version, '2.9'):
|
||||
self.shares_v2_client.wait_for_access_rule_status(
|
||||
self.share["id"], rule["id"], "active")
|
||||
else:
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
self.share["id"], "active", status_attr='access_rules_status',
|
||||
version=version)
|
||||
|
||||
# try create duplicate of rule
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_access_rule,
|
||||
self.share["id"], access_type, access_to)
|
||||
else:
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.create_access_rule,
|
||||
self.share["id"], access_type, access_to,
|
||||
version=version)
|
||||
|
||||
# delete rule and wait for deletion
|
||||
if utils.is_microversion_eq(version, '1.0'):
|
||||
self.shares_client.delete_access_rule(self.share["id"],
|
||||
rule["id"])
|
||||
self.shares_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share["id"])
|
||||
else:
|
||||
self.shares_v2_client.delete_access_rule(self.share["id"],
|
||||
rule["id"])
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule["id"], share_id=self.share["id"], version=version)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_add_access_rule_on_share_with_no_host(self):
|
||||
access_type, access_to = self._get_access_rule_data_from_config()
|
||||
extra_specs = self.add_extra_specs_to_dict(
|
||||
{"share_backend_name": 'invalid_backend'})
|
||||
share_type = self.create_share_type('invalid_backend',
|
||||
extra_specs=extra_specs,
|
||||
client=self.admin_client,
|
||||
cleanup_in_class=False)
|
||||
share_type = share_type['share_type']
|
||||
share = self.create_share(share_type_id=share_type['id'],
|
||||
cleanup_in_class=False,
|
||||
wait_for_status=False)
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
share['id'], constants.STATUS_ERROR)
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.admin_client.create_access_rule,
|
||||
share["id"], access_type, access_to)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareIpRulesForCIFSNegativeTest(ShareIpRulesForNFSNegativeTest):
|
||||
protocol = "cifs"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareUserRulesForNFSNegativeTest(base.BaseSharesTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareUserRulesForNFSNegativeTest, cls).resource_setup()
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_user_rules_for_protocols):
|
||||
msg = "USER rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
# create share
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_wrong_input_2(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "user",
|
||||
"try+")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_empty_key(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "user", "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_too_little_key(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "user", "abc")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_too_big_key(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "user", "a" * 256)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_wrong_input_1(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "user",
|
||||
"try+")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_create_access_rule_user_to_snapshot(self, client_name):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.snap["id"],
|
||||
access_type="user",
|
||||
access_to="fakeuser")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_user_with_wrong_share_id(self, client_name):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
"wrong_share_id",
|
||||
access_type="user",
|
||||
access_to="fakeuser")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_with_wrong_level(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"],
|
||||
'user',
|
||||
CONF.share.username_for_user_rules,
|
||||
'su')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareUserRulesForCIFSNegativeTest(ShareUserRulesForNFSNegativeTest):
|
||||
protocol = "cifs"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareCertRulesForGLUSTERFSNegativeTest(base.BaseSharesTest):
|
||||
protocol = "glusterfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareCertRulesForGLUSTERFSNegativeTest, cls).resource_setup()
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_cert_rules_for_protocols):
|
||||
msg = "CERT rule tests for %s protocol are disabled" % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
# create share
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_cert_with_empty_common_name(self, client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "cert", "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_cert_with_whitespace_common_name(self,
|
||||
client_name):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "cert", " ")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_cert_with_too_big_common_name(self,
|
||||
client_name):
|
||||
# common name cannot be more than 64 characters long
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "cert", "a" * 65)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_cert_to_snapshot(self, client_name):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.snap["id"],
|
||||
access_type="cert",
|
||||
access_to="fakeclient1.com")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_cert_with_wrong_share_id(self, client_name):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
"wrong_share_id",
|
||||
access_type="cert",
|
||||
access_to="fakeclient2.com")
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareCephxRulesForCephFSNegativeTest(base.BaseSharesTest):
|
||||
protocol = "cephfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareCephxRulesForCephFSNegativeTest, cls).resource_setup()
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_cephx_rules_for_protocols):
|
||||
msg = ("CEPHX rule tests for %s protocol are disabled" %
|
||||
cls.protocol)
|
||||
raise cls.skipException(msg)
|
||||
# create share
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.access_type = "cephx"
|
||||
cls.access_to = "david"
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('jane.doe', u"bj\u00F6rn")
|
||||
def test_create_access_rule_cephx_with_invalid_cephx_id(self, access_to):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.create_access_rule,
|
||||
self.share["id"], self.access_type, access_to)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_access_rule_cephx_with_wrong_level(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.create_access_rule,
|
||||
self.share["id"], self.access_type, self.access_to,
|
||||
access_level="su")
|
||||
|
||||
|
||||
def skip_if_cephx_access_type_not_supported_by_client(self, client):
|
||||
if client == 'shares_client':
|
||||
version = '1.0'
|
||||
else:
|
||||
version = LATEST_MICROVERSION
|
||||
if (CONF.share.enable_cephx_rules_for_protocols and
|
||||
utils.is_microversion_lt(version, '2.13')):
|
||||
msg = ("API version %s does not support cephx access type, need "
|
||||
"version >= 2.13." % version)
|
||||
raise self.skipException(msg)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareRulesNegativeTest(base.BaseSharesTest):
|
||||
# Tests independent from rule type and share protocol
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareRulesNegativeTest, cls).resource_setup()
|
||||
if not (any(p in CONF.share.enable_ip_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_user_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_cert_rules_for_protocols
|
||||
for p in cls.protocols) or
|
||||
any(p in CONF.share.enable_cephx_rules_for_protocols
|
||||
for p in cls.protocols)):
|
||||
cls.message = "Rule tests are disabled"
|
||||
raise cls.skipException(cls.message)
|
||||
# create share
|
||||
cls.share = cls.create_share()
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_delete_access_rule_with_wrong_id(self, client_name):
|
||||
skip_if_cephx_access_type_not_supported_by_client(self, client_name)
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).delete_access_rule,
|
||||
self.share["id"], "wrong_rule_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_ip_with_wrong_type(self, client_name):
|
||||
skip_if_cephx_access_type_not_supported_by_client(self, client_name)
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.share["id"], "wrong_type", "1.2.3.4")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_create_access_rule_ip_to_snapshot(self, client_name):
|
||||
skip_if_cephx_access_type_not_supported_by_client(self, client_name)
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
self.snap["id"])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareRulesAPIOnlyNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_create_access_rule_ip_with_wrong_share_id(self, client_name):
|
||||
skip_if_cephx_access_type_not_supported_by_client(self, client_name)
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
getattr(self, client_name).create_access_rule,
|
||||
"wrong_share_id")
|
@ -1,33 +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.lib import exceptions as lib_exc
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
class SchedulerStatsNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_pools_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.list_pools)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_pools_detailed_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.list_pools,
|
||||
detail=True)
|
@ -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.
|
||||
|
||||
from oslo_log import log
|
||||
import six
|
||||
from tempest import config
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class SecurityServiceListMixin(object):
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_security_services(self):
|
||||
listed = self.shares_client.list_security_services()
|
||||
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))
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id", "status", "type", ]
|
||||
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_security_services_with_detail(self):
|
||||
listed = self.shares_client.list_security_services(detailed=True)
|
||||
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))
|
||||
|
||||
# verify keys
|
||||
keys = [
|
||||
"name", "id", "status", "description",
|
||||
"domain", "server", "dns_ip", "user", "password", "type",
|
||||
"created_at", "updated_at", "project_id",
|
||||
]
|
||||
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_list_security_services_filter_by_share_network(self):
|
||||
sn = self.shares_client.get_share_network(
|
||||
self.shares_client.share_network_id)
|
||||
fresh_sn = []
|
||||
for i in range(2):
|
||||
sn = self.create_share_network(
|
||||
neutron_net_id=sn["neutron_net_id"],
|
||||
neutron_subnet_id=sn["neutron_subnet_id"])
|
||||
fresh_sn.append(sn)
|
||||
|
||||
self.shares_client.add_sec_service_to_share_network(
|
||||
fresh_sn[0]["id"], self.ss_ldap["id"])
|
||||
self.shares_client.add_sec_service_to_share_network(
|
||||
fresh_sn[1]["id"], self.ss_kerberos["id"])
|
||||
|
||||
listed = self.shares_client.list_security_services(
|
||||
params={'share_network_id': fresh_sn[0]['id']})
|
||||
self.assertEqual(1, len(listed))
|
||||
self.assertEqual(self.ss_ldap['id'], listed[0]['id'])
|
||||
|
||||
keys = ["name", "id", "status", "type", ]
|
||||
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_security_services_detailed_filter_by_ss_attributes(self):
|
||||
search_opts = {
|
||||
'name': 'ss_ldap',
|
||||
'type': 'ldap',
|
||||
'user': 'fake_user',
|
||||
'server': 'fake_server_1',
|
||||
'dns_ip': '1.1.1.1',
|
||||
'domain': 'fake_domain_1',
|
||||
}
|
||||
listed = self.shares_client.list_security_services(
|
||||
detailed=True,
|
||||
params=search_opts)
|
||||
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
|
||||
for ss in listed:
|
||||
self.assertTrue(all(ss[key] == value for key, value
|
||||
in search_opts.items()))
|
||||
|
||||
|
||||
class SecurityServicesTest(base.BaseSharesTest,
|
||||
SecurityServiceListMixin):
|
||||
def setUp(self):
|
||||
super(SecurityServicesTest, 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_create_delete_security_service(self):
|
||||
data = self.generate_security_service_data()
|
||||
self.service_names = ["ldap", "kerberos", "active_directory"]
|
||||
for ss_name in self.service_names:
|
||||
ss = self.create_security_service(ss_name, **data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
self.assertEqual(ss_name, ss["type"])
|
||||
self.shares_client.delete_security_service(ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_get_security_service(self):
|
||||
data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(**data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
|
||||
get = self.shares_client.get_security_service(ss["id"])
|
||||
self.assertDictContainsSubset(data, get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_security_service(self):
|
||||
data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(**data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
|
||||
upd_data = self.generate_security_service_data()
|
||||
updated = self.shares_client.update_security_service(
|
||||
ss["id"], **upd_data)
|
||||
|
||||
get = self.shares_client.get_security_service(ss["id"])
|
||||
self.assertDictContainsSubset(upd_data, updated)
|
||||
self.assertDictContainsSubset(upd_data, get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_try_update_valid_keys_sh_server_exists(self):
|
||||
ss_data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(**ss_data)
|
||||
|
||||
sn = self.shares_client.get_share_network(
|
||||
self.shares_client.share_network_id)
|
||||
fresh_sn = self.create_share_network(
|
||||
neutron_net_id=sn["neutron_net_id"],
|
||||
neutron_subnet_id=sn["neutron_subnet_id"])
|
||||
|
||||
self.shares_client.add_sec_service_to_share_network(
|
||||
fresh_sn["id"], ss["id"])
|
||||
|
||||
# Security service with fake data is used, so if we use backend driver
|
||||
# that fails on wrong data, we expect error here.
|
||||
# We require any share that uses our share-network.
|
||||
try:
|
||||
self.create_share(
|
||||
share_network_id=fresh_sn["id"], cleanup_in_class=False)
|
||||
except Exception as e:
|
||||
# we do wait for either 'error' or 'available' status because
|
||||
# it is the only available statuses for proper deletion.
|
||||
LOG.warning("Caught exception. It is expected in case backend "
|
||||
"fails having security-service with improper data "
|
||||
"that leads to share-server creation error. "
|
||||
"%s", six.text_type(e))
|
||||
|
||||
update_data = {
|
||||
"name": "name",
|
||||
"description": "new_description",
|
||||
}
|
||||
updated = self.shares_client.update_security_service(
|
||||
ss["id"], **update_data)
|
||||
self.assertDictContainsSubset(update_data, updated)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_security_services_filter_by_invalid_opt(self):
|
||||
listed = self.shares_client.list_security_services(
|
||||
params={'fake_opt': 'some_value'})
|
||||
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))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_try_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))
|
@ -1,70 +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
|
||||
|
||||
|
||||
class SecurityServicesMappingTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SecurityServicesMappingTest, cls).resource_setup()
|
||||
cls.cl = cls.shares_client
|
||||
|
||||
def setUp(self):
|
||||
super(SecurityServicesMappingTest, self).setUp()
|
||||
|
||||
# create share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
self.sn = self.create_share_network(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, self.sn)
|
||||
|
||||
# create security service
|
||||
data = self.generate_security_service_data()
|
||||
|
||||
self.ss = self.create_security_service(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, self.ss)
|
||||
|
||||
# Add security service to share network
|
||||
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_map_ss_to_sn_and_list(self):
|
||||
|
||||
# List security services for share network
|
||||
ls = self.cl.list_sec_services_for_share_network(self.sn["id"])
|
||||
self.assertEqual(1, len(ls))
|
||||
for key in ["status", "id", "name"]:
|
||||
self.assertIn(self.ss[key], ls[0][key])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_map_ss_to_sn_and_delete(self):
|
||||
|
||||
# Remove security service from share network
|
||||
self.cl.remove_sec_service_from_share_network(
|
||||
self.sn["id"], self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_remap_ss_to_sn(self):
|
||||
|
||||
# Remove security service from share network
|
||||
self.cl.remove_sec_service_from_share_network(
|
||||
self.sn["id"], self.ss["id"])
|
||||
|
||||
# Add security service to share network again
|
||||
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
|
@ -1,173 +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 oslo_log import log
|
||||
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
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class SecServicesMappingNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SecServicesMappingNegativeTest, cls).resource_setup()
|
||||
cls.sn = cls.create_share_network(cleanup_in_class=True)
|
||||
cls.ss = cls.create_security_service(cleanup_in_class=True)
|
||||
cls.cl = cls.shares_client
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_sec_service_twice_to_share_network(self):
|
||||
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
self.sn["id"], self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_nonexistant_sec_service_to_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
self.sn["id"], "wrong_ss_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_empty_sec_service_id_to_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
self.sn["id"], "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_sec_service_to_nonexistant_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
"wrong_sn_id", self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_sec_service_to_share_network_with_empty_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
"", self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_sec_services_for_nonexistant_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.list_sec_services_for_share_network,
|
||||
"wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_nonexistant_sec_service_from_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.remove_sec_service_from_share_network,
|
||||
self.sn["id"], "wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_sec_service_from_nonexistant_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.remove_sec_service_from_share_network,
|
||||
"wrong_id", self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_nonexistant_ss_from_nonexistant_sn(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.cl.remove_sec_service_from_share_network,
|
||||
"wrong_id", "wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_delete_ss_from_sn_used_by_share_server(self):
|
||||
sn = self.shares_client.get_share_network(
|
||||
self.shares_client.share_network_id)
|
||||
fresh_sn = self.create_share_network(
|
||||
neutron_net_id=sn["neutron_net_id"],
|
||||
neutron_subnet_id=sn["neutron_subnet_id"])
|
||||
|
||||
self.shares_client.add_sec_service_to_share_network(
|
||||
fresh_sn["id"], self.ss["id"])
|
||||
|
||||
# Security service with fake data is used, so if we use backend driver
|
||||
# that fails on wrong data, we expect error here.
|
||||
# We require any share that uses our share-network.
|
||||
try:
|
||||
self.create_share(
|
||||
share_network_id=fresh_sn["id"], cleanup_in_class=False)
|
||||
except Exception as e:
|
||||
# we do wait for either 'error' or 'available' status because
|
||||
# it is the only available statuses for proper deletion.
|
||||
LOG.warning("Caught exception. It is expected in case backend "
|
||||
"fails having security-service with improper data "
|
||||
"that leads to share-server creation error. "
|
||||
"%s", six.text_type(e))
|
||||
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.cl.remove_sec_service_from_share_network,
|
||||
fresh_sn["id"],
|
||||
self.ss["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_map_two_ss_with_same_type_to_sn(self):
|
||||
# create share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
sn = self.create_share_network(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, sn)
|
||||
|
||||
# create security services with same type
|
||||
security_services = []
|
||||
for i in range(2):
|
||||
data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
security_services.insert(i, ss)
|
||||
|
||||
# Add security service to share network
|
||||
self.cl.add_sec_service_to_share_network(
|
||||
sn["id"], security_services[0]["id"])
|
||||
|
||||
# Try to add security service with same type
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.cl.add_sec_service_to_share_network,
|
||||
sn["id"], security_services[1]["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_ss_that_assigned_to_sn(self):
|
||||
# create share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
sn = self.create_share_network(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, sn)
|
||||
|
||||
# create security service
|
||||
data = self.generate_security_service_data()
|
||||
|
||||
ss = self.create_security_service(client=self.cl, **data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
|
||||
# Add security service to share network
|
||||
self.cl.add_sec_service_to_share_network(sn["id"], ss["id"])
|
||||
|
||||
# Try delete ss, that has been assigned to some sn
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.cl.delete_security_service,
|
||||
ss["id"], )
|
||||
|
||||
# remove seurity service from share-network
|
||||
self.cl.remove_sec_service_from_share_network(sn["id"], ss["id"])
|
@ -1,122 +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 oslo_log import log
|
||||
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
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class SecurityServicesNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_security_service_with_empty_type(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_security_service, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_security_service_with_wrong_type(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_security_service,
|
||||
"wrong_type")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_security_service_without_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_security_service, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_security_service_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_security_service,
|
||||
"wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_security_service_without_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_security_service, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_security_service_with_wrong_type(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_security_service,
|
||||
"wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_nonexistant_security_service(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.update_security_service,
|
||||
"wrong_id", name="name")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_security_service_with_empty_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.update_security_service,
|
||||
"", name="name")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_try_update_invalid_keys_sh_server_exists(self):
|
||||
ss_data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(**ss_data)
|
||||
|
||||
sn = self.shares_client.get_share_network(
|
||||
self.shares_client.share_network_id)
|
||||
fresh_sn = self.create_share_network(
|
||||
neutron_net_id=sn["neutron_net_id"],
|
||||
neutron_subnet_id=sn["neutron_subnet_id"])
|
||||
|
||||
self.shares_client.add_sec_service_to_share_network(
|
||||
fresh_sn["id"], ss["id"])
|
||||
|
||||
# Security service with fake data is used, so if we use backend driver
|
||||
# that fails on wrong data, we expect error here.
|
||||
# We require any share that uses our share-network.
|
||||
try:
|
||||
self.create_share(
|
||||
share_network_id=fresh_sn["id"], cleanup_in_class=False)
|
||||
except Exception as e:
|
||||
# we do wait for either 'error' or 'available' status because
|
||||
# it is the only available statuses for proper deletion.
|
||||
LOG.warning("Caught exception. It is expected in case backend "
|
||||
"fails having security-service with improper data "
|
||||
"that leads to share-server creation error. "
|
||||
"%s", six.text_type(e))
|
||||
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.update_security_service,
|
||||
ss["id"],
|
||||
user="new_user")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_deleted_security_service(self):
|
||||
data = self.generate_security_service_data()
|
||||
ss = self.create_security_service(**data)
|
||||
self.assertDictContainsSubset(data, ss)
|
||||
|
||||
self.shares_client.delete_security_service(ss["id"])
|
||||
|
||||
# try get deleted security service entity
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_security_service,
|
||||
ss["id"])
|
@ -1,401 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
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 ShareGroupActionsTest(base.BaseSharesTest):
|
||||
"""Covers share group functionality."""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupActionsTest, cls).resource_setup()
|
||||
|
||||
# Create first share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name, description=cls.share_group_desc)
|
||||
|
||||
# Create second share group for purposes of sorting and snapshot
|
||||
# filtering
|
||||
cls.share_group2 = cls.create_share_group(
|
||||
name=cls.share_group_name, description=cls.share_group_desc)
|
||||
|
||||
# Create 2 shares - inside first and second share groups
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share_size = 1
|
||||
cls.share_size2 = 2
|
||||
cls.shares = cls.create_shares([
|
||||
{'kwargs': {
|
||||
'name': cls.share_name,
|
||||
'description': cls.share_desc,
|
||||
'size': size,
|
||||
'share_group_id': sg_id,
|
||||
'experimental': True,
|
||||
}} for size, sg_id in ((cls.share_size, cls.share_group['id']),
|
||||
(cls.share_size2, cls.share_group['id']),
|
||||
(cls.share_size, cls.share_group2['id']))
|
||||
])
|
||||
|
||||
# Create share group snapshots
|
||||
cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
|
||||
cls.sg_snap_desc = data_utils.rand_name("tempest-sg-snap-desc")
|
||||
|
||||
cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group["id"],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc,
|
||||
)
|
||||
|
||||
cls.sg_snapshot2 = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group2['id'],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_min_supported_sg_microversion(self):
|
||||
|
||||
# Get share group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
share_group['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys))
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.share_group_name, share_group["name"])
|
||||
self.assertEqual(self.share_group_desc, share_group["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_min_supported_sg_microversion(self):
|
||||
|
||||
# Get share
|
||||
share = self.shares_v2_client.get_share(
|
||||
self.shares[0]['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True)
|
||||
|
||||
# Verify keys
|
||||
expected_keys = {
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "share_proto", "name", "snapshot_id",
|
||||
"id", "size", "share_group_id",
|
||||
}
|
||||
actual_keys = set(share.keys())
|
||||
self.assertTrue(
|
||||
expected_keys.issubset(actual_keys),
|
||||
'Not all required keys returned for share %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
share['id'], expected_keys, actual_keys))
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.share_name, share["name"])
|
||||
self.assertEqual(self.share_desc, share["description"])
|
||||
self.assertEqual(self.share_size, int(share["size"]))
|
||||
self.assertEqual(self.share_group["id"], share["share_group_id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_share_groups_min(self):
|
||||
|
||||
# List share groups
|
||||
share_groups = self.shares_v2_client.list_share_groups(
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Verify keys
|
||||
self.assertGreater(len(share_groups), 0)
|
||||
for sg in share_groups:
|
||||
keys = set(sg.keys())
|
||||
self.assertEqual(
|
||||
constants.SHARE_GROUP_SIMPLE_KEYS,
|
||||
keys,
|
||||
'Incorrect keys returned for share group %s. '
|
||||
'Expected: %s, found %s' % (
|
||||
sg['id'],
|
||||
constants.SHARE_GROUP_SIMPLE_KEYS,
|
||||
','.join(keys)))
|
||||
|
||||
# Share group ids are in list exactly once
|
||||
for sg_id in (self.share_group["id"], self.share_group2["id"]):
|
||||
gen = [sg["id"] for sg in share_groups if sg["id"] == sg_id]
|
||||
msg = ("Expected id %s exactly once in share group list" % sg_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(constants.MIN_SHARE_GROUP_MICROVERSION, '2.36')
|
||||
def test_list_share_groups_with_detail_min(self, version):
|
||||
params = None
|
||||
if utils.is_microversion_ge(version, '2.36'):
|
||||
params = {'name~': 'tempest', 'description~': 'tempest'}
|
||||
# List share groups
|
||||
share_groups = self.shares_v2_client.list_share_groups(
|
||||
detailed=True, params=params, version=version)
|
||||
|
||||
# Verify keys
|
||||
for sg in share_groups:
|
||||
keys = set(sg.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(
|
||||
keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
sg['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
','.join(keys),
|
||||
)
|
||||
)
|
||||
|
||||
# Share group ids are in list exactly once
|
||||
for group_id in (self.share_group["id"], self.share_group2["id"]):
|
||||
gen = [share_group["id"] for share_group in share_groups
|
||||
if share_group["id"] == group_id]
|
||||
msg = ("Expected id %s exactly once in share group list" %
|
||||
group_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_by_share_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': self.share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True,
|
||||
)
|
||||
|
||||
share_ids = [share['id'] for share in shares]
|
||||
|
||||
self.assertEqual(
|
||||
2, len(shares),
|
||||
'Incorrect number of shares returned. '
|
||||
'Expected 2, got %s' % len(shares))
|
||||
self.assertIn(
|
||||
self.shares[0]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s' % (
|
||||
self.shares[0]['id'], share_ids))
|
||||
self.assertIn(
|
||||
self.shares[1]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s' % (
|
||||
self.shares[0]['id'], share_ids))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_snapshot_min(self):
|
||||
# Get share group snapshot
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(sg_snapshot.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(
|
||||
actual_keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
sg_snapshot['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys,
|
||||
)
|
||||
)
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.sg_snap_name, sg_snapshot["name"])
|
||||
self.assertEqual(self.sg_snap_desc, sg_snapshot["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_snapshot_members_min(self):
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
sg_snapshot_members = sg_snapshot['members']
|
||||
member_share_ids = [m['share_id'] for m in sg_snapshot_members]
|
||||
self.assertEqual(
|
||||
2, len(sg_snapshot_members),
|
||||
'Unexpected number of share group snapshot members. '
|
||||
'Expected 2, got %s.' % len(sg_snapshot_members))
|
||||
# Verify each share is represented in the share group snapshot
|
||||
# appropriately
|
||||
for share_id in (self.shares[0]['id'], self.shares[1]['id']):
|
||||
self.assertIn(
|
||||
share_id, member_share_ids,
|
||||
'Share missing %s missing from share group '
|
||||
'snapshot. Found %s.' % (share_id, member_share_ids))
|
||||
for share in (self.shares[0], self.shares[1]):
|
||||
for member in sg_snapshot_members:
|
||||
if share['id'] == member['share_id']:
|
||||
self.assertEqual(share['size'], member['size'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_group_from_populated_share_group_snapshot_min(self):
|
||||
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
snapshot_members = sg_snapshot['members']
|
||||
|
||||
new_share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
source_share_group_snapshot_id=self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
new_share_group = self.shares_v2_client.get_share_group(
|
||||
new_share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify that share_network information matches source share group
|
||||
self.assertEqual(
|
||||
self.share_group['share_network_id'],
|
||||
new_share_group['share_network_id'])
|
||||
|
||||
new_shares = self.shares_v2_client.list_shares(
|
||||
params={'share_group_id': new_share_group['id']},
|
||||
detailed=True,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True,
|
||||
)
|
||||
|
||||
# Verify each new share is available
|
||||
for share in new_shares:
|
||||
self.assertEqual(
|
||||
'available', share['status'],
|
||||
'Share %s is not in available status.' % share['id'])
|
||||
|
||||
# Verify each sgsnapshot member is represented in the new sg
|
||||
# appropriately
|
||||
share_source_member_ids = [
|
||||
share['source_share_group_snapshot_member_id']
|
||||
for share in new_shares]
|
||||
for member in snapshot_members:
|
||||
self.assertIn(
|
||||
member['id'], share_source_member_ids,
|
||||
'Share group snapshot member %s not represented by '
|
||||
'share group %s.' % (member['id'], new_share_group['id']))
|
||||
for share in new_shares:
|
||||
if (share['source_share_group_snapshot_member_id'] == (
|
||||
member['id'])):
|
||||
self.assertEqual(member['size'], share['size'])
|
||||
self.assertEqual(
|
||||
self.share_group['share_network_id'],
|
||||
share['share_network_id'])
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupRenameTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupRenameTest, cls).resource_setup()
|
||||
|
||||
# Create share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name,
|
||||
description=cls.share_group_desc,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_share_group_min(self):
|
||||
|
||||
# Get share_group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION
|
||||
)
|
||||
self.assertEqual(self.share_group_name, share_group["name"])
|
||||
self.assertEqual(self.share_group_desc, share_group["description"])
|
||||
|
||||
# Update share_group
|
||||
new_name = data_utils.rand_name("tempest-new-name")
|
||||
new_desc = data_utils.rand_name("tempest-new-description")
|
||||
updated = self.shares_v2_client.update_share_group(
|
||||
share_group["id"],
|
||||
name=new_name,
|
||||
description=new_desc,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(new_name, updated["name"])
|
||||
self.assertEqual(new_desc, updated["description"])
|
||||
|
||||
# Get share_group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(new_name, share_group["name"])
|
||||
self.assertEqual(new_desc, share_group["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_update_read_share_group_with_unicode_min(self):
|
||||
value1 = u'ಠ_ಠ'
|
||||
value2 = u'ಠ_ರೃ'
|
||||
|
||||
# Create share_group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
name=value1,
|
||||
description=value1,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(value1, share_group["name"])
|
||||
self.assertEqual(value1, share_group["description"])
|
||||
|
||||
# Update share group
|
||||
updated = self.shares_v2_client.update_share_group(
|
||||
share_group["id"],
|
||||
name=value2,
|
||||
description=value2,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(value2, updated["name"])
|
||||
self.assertEqual(value2, updated["description"])
|
||||
|
||||
# Get share group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.assertEqual(value2, share_group["name"])
|
||||
self.assertEqual(value2, share_group["description"])
|
@ -1,222 +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 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)
|
||||
@ddt.ddt
|
||||
class ShareGroupsTest(base.BaseSharesTest):
|
||||
"""Covers share group functionality."""
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_populate_delete_share_group_min(self):
|
||||
# Create a share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
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}
|
||||
)
|
||||
# Populate
|
||||
share = self.create_share(
|
||||
share_group_id=share_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True)
|
||||
|
||||
# Delete
|
||||
params = {"share_group_id": share_group['id']}
|
||||
self.shares_v2_client.delete_share(
|
||||
share['id'],
|
||||
params=params,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.shares_v2_client.delete_share_group(
|
||||
share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_group_id=share_group['id'])
|
||||
|
||||
# Verify
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group, share_group['id'])
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound, self.shares_client.get_share, share['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_delete_empty_share_group_snapshot_min(self):
|
||||
# Create base share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Create share group snapshot
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
share_group["id"],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
keys = set(sg_snapshot.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group snapshot '
|
||||
'response. Expected %(e)s, got %(a)s.' % {
|
||||
"e": constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS,
|
||||
"a": keys})
|
||||
|
||||
sg_snapshot_members = sg_snapshot['members']
|
||||
self.assertEmpty(
|
||||
sg_snapshot_members,
|
||||
'Expected 0 share_group_snapshot members, got %s' % len(
|
||||
sg_snapshot_members))
|
||||
|
||||
# Delete snapshot
|
||||
self.shares_v2_client.delete_share_group_snapshot(
|
||||
sg_snapshot["id"], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_group_snapshot_id=sg_snapshot["id"])
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group_snapshot,
|
||||
sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_group_from_empty_share_group_snapshot_min(self):
|
||||
# Create base share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Create share group snapshot
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
share_group["id"], cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
snapshot_members = sg_snapshot['members']
|
||||
|
||||
self.assertEmpty(
|
||||
snapshot_members,
|
||||
'Expected 0 share group snapshot members, got %s' %
|
||||
len(snapshot_members))
|
||||
|
||||
new_share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
source_share_group_snapshot_id=sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
new_shares = self.shares_v2_client.list_shares(
|
||||
params={'share_group_id': new_share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION, experimental=True)
|
||||
|
||||
self.assertEmpty(
|
||||
new_shares, 'Expected 0 new shares, got %s' % len(new_shares))
|
||||
|
||||
msg = ('Expected source_ishare_group_snapshot_id %s '
|
||||
'as source of share group %s' % (
|
||||
sg_snapshot['id'],
|
||||
new_share_group['source_share_group_snapshot_id']))
|
||||
self.assertEqual(
|
||||
new_share_group['source_share_group_snapshot_id'],
|
||||
sg_snapshot['id'],
|
||||
msg)
|
||||
|
||||
msg = ('Unexpected share_types on new share group. Expected '
|
||||
'%s, got %s.' % (share_group['share_types'],
|
||||
new_share_group['share_types']))
|
||||
self.assertEqual(
|
||||
sorted(share_group['share_types']),
|
||||
sorted(new_share_group['share_types']), msg)
|
||||
|
||||
# Assert the share_network information is the same
|
||||
msg = 'Expected share_network %s as share_network of cg %s' % (
|
||||
share_group['share_network_id'],
|
||||
new_share_group['share_network_id'])
|
||||
self.assertEqual(
|
||||
share_group['share_network_id'],
|
||||
new_share_group['share_network_id'],
|
||||
msg)
|
||||
|
||||
@base.skip_if_microversion_lt("2.34")
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(
|
||||
'sg', 'sg_and_share', 'none',
|
||||
)
|
||||
def test_create_sg_and_share_specifying_az(self, where_specify_az):
|
||||
# Get list of existing availability zones, at least one always
|
||||
# should exist
|
||||
azs = self.shares_v2_client.list_availability_zones()
|
||||
|
||||
sg_kwargs = {
|
||||
'version': '2.34',
|
||||
'cleanup_in_class': False,
|
||||
}
|
||||
if where_specify_az in ('sg', 'sg_and_share'):
|
||||
sg_kwargs['availability_zone'] = azs[0]['name']
|
||||
|
||||
# Create share group
|
||||
share_group = self.create_share_group(**sg_kwargs)
|
||||
|
||||
# Get latest share group info
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
share_group['id'], '2.34')
|
||||
|
||||
self.assertIn('availability_zone', share_group)
|
||||
if where_specify_az in ('sg', 'sg_and_share'):
|
||||
self.assertEqual(azs[0]['name'], share_group['availability_zone'])
|
||||
else:
|
||||
self.assertIn(
|
||||
share_group['availability_zone'], [az['name'] for az in azs])
|
||||
|
||||
# Test 'consistent_snapshot_support' as part of 2.33 API change
|
||||
self.assertIn('consistent_snapshot_support', share_group)
|
||||
self.assertIn(
|
||||
share_group['consistent_snapshot_support'], ('host', 'pool', None))
|
||||
|
||||
s_kwargs = {
|
||||
'share_group_id': share_group['id'],
|
||||
'version': '2.33',
|
||||
'cleanup_in_class': False,
|
||||
'experimental': True,
|
||||
}
|
||||
if where_specify_az == 'sg_and_share':
|
||||
s_kwargs['availability_zone'] = azs[0]['name']
|
||||
|
||||
# Create share in share group
|
||||
share = self.create_share(**s_kwargs)
|
||||
|
||||
# Get latest share info
|
||||
share = self.shares_v2_client.get_share(share['id'], '2.34')
|
||||
|
||||
# Verify that share always has the same AZ as share group does
|
||||
self.assertEqual(
|
||||
share_group['availability_zone'], share['availability_zone'])
|
@ -1,273 +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
|
||||
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 ShareGroupsNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupsNegativeTest, cls).resource_setup()
|
||||
# Create a share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name,
|
||||
description=cls.share_group_desc
|
||||
)
|
||||
# Create a share in the share group
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share_size = 1
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
size=cls.share_size,
|
||||
share_group_id=cls.share_group['id'],
|
||||
experimental=True,
|
||||
)
|
||||
# Create a share group snapshot of the share group
|
||||
cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
|
||||
cls.sg_snap_desc = data_utils.rand_name(
|
||||
"tempest-group-snap-description")
|
||||
cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group["id"],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_source_sg_snapshot_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
source_share_group_snapshot_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_nonexistent_source_sg_snapshot_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
source_share_group_snapshot_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_share_network_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_network_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_group_with_nonexistent_share_network_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_network_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_share_type_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_type_ids=['foobar'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_nonexistent_share_type_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_type_ids=[self.share['id']],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_snapshot_with_invalid_sg_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_snapshot_wait_for_active,
|
||||
'foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_snapshot_with_nonexistent_sg_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_snapshot_wait_for_active,
|
||||
self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group,
|
||||
"invalid_share_group_id",
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_sg_without_passing_group_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group,
|
||||
'', version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.update_share_group,
|
||||
'invalid_share_group_id',
|
||||
name='new_name',
|
||||
description='new_description',
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
"invalid_share_group_id",
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_without_passing_sg_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
'', version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_in_use_by_sg_snapshot_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_share_in_use_by_sg_snapshot_min(self):
|
||||
params = {'share_group_id': self.share['share_group_id']}
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.delete_share,
|
||||
self.share['id'],
|
||||
params=params,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_containing_a_share_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Verify share group is not put into error state from conflict
|
||||
sg = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.assertEqual('available', sg['status'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_invalid_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': 'foobar'},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_nonexistent_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': self.share['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_empty_share_group_id_min(self):
|
||||
share_group = self.create_share_group(
|
||||
name='tempest_sg',
|
||||
description='tempest_sg_desc',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_nonexistent_az_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.create_share_group,
|
||||
name='tempest_sg',
|
||||
description='tempest_sg_desc',
|
||||
availability_zone='fake_nonexistent_az',
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@base.skip_if_microversion_lt("2.34")
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_and_share_with_different_azs(self):
|
||||
azs = self.shares_v2_client.list_availability_zones()
|
||||
|
||||
if len(azs) < 2:
|
||||
raise self.skipException(
|
||||
'Test requires presence of at least 2 availability zones.')
|
||||
else:
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'], '2.34')
|
||||
different_az = [
|
||||
az['name']
|
||||
for az in azs
|
||||
if az['name'] != share_group['availability_zone']
|
||||
][0]
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share,
|
||||
share_group_id=self.share_group['id'],
|
||||
availability_zone=different_az,
|
||||
version='2.34')
|
@ -1,298 +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
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class ShareNetworkListMixin(object):
|
||||
|
||||
@tc.attr("gate", "smoke", )
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_share_networks(self):
|
||||
listed = self.shares_client.list_share_networks()
|
||||
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id"]
|
||||
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_try_list_share_networks_all_tenants(self):
|
||||
listed = self.shares_client.list_share_networks_with_detail(
|
||||
params={'all_tenants': 1})
|
||||
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id"]
|
||||
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_try_list_share_networks_project_id(self):
|
||||
listed = self.shares_client.list_share_networks_with_detail(
|
||||
params={'project_id': 'some_project'})
|
||||
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id"]
|
||||
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_share_networks_with_detail(self):
|
||||
listed = self.shares_v2_client.list_share_networks_with_detail()
|
||||
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
|
||||
|
||||
# verify keys
|
||||
keys = [
|
||||
"name", "id", "description", "network_type",
|
||||
"project_id", "cidr", "ip_version",
|
||||
"neutron_net_id", "neutron_subnet_id",
|
||||
"created_at", "updated_at", "segmentation_id",
|
||||
]
|
||||
|
||||
# In v2.18 and beyond, we expect gateway.
|
||||
if utils.is_microversion_supported('2.18'):
|
||||
keys.append('gateway')
|
||||
|
||||
# In v2.20 and beyond, we expect mtu.
|
||||
if utils.is_microversion_supported('2.20'):
|
||||
keys.append('mtu')
|
||||
|
||||
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_share_networks_filter_by_ss(self):
|
||||
listed = self.shares_client.list_share_networks_with_detail(
|
||||
{'security_service_id': self.ss_ldap['id']})
|
||||
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
|
||||
for sn in listed))
|
||||
for sn in listed:
|
||||
ss_list = self.shares_client.list_sec_services_for_share_network(
|
||||
sn['id'])
|
||||
self.assertTrue(any(ss['id'] == self.ss_ldap['id']
|
||||
for ss in ss_list))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_lt("2.36")
|
||||
def test_list_share_networks_like_filter(self):
|
||||
valid_filter_opts = {
|
||||
'name': 'sn_with_ldap_ss',
|
||||
'description': 'fake',
|
||||
}
|
||||
|
||||
listed = self.shares_v2_client.list_share_networks_with_detail(
|
||||
{'name~': 'ldap_ss', 'description~': 'fa'})
|
||||
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
|
||||
for sn in listed))
|
||||
for sn in listed:
|
||||
self.assertTrue(all(value in sn[key] for key, value in
|
||||
valid_filter_opts.items()))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_list_share_networks_all_filter_opts(self):
|
||||
valid_filter_opts = {
|
||||
'created_before': '2002-10-10',
|
||||
'created_since': '2001-01-01',
|
||||
'neutron_net_id': '1111',
|
||||
'neutron_subnet_id': '2222',
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 1000,
|
||||
'cidr': '10.0.0.0/24',
|
||||
'ip_version': 4,
|
||||
'name': 'sn_with_ldap_ss'
|
||||
}
|
||||
|
||||
listed = self.shares_client.list_share_networks_with_detail(
|
||||
valid_filter_opts)
|
||||
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
|
||||
for sn in listed))
|
||||
created_before = valid_filter_opts.pop('created_before')
|
||||
created_since = valid_filter_opts.pop('created_since')
|
||||
for sn in listed:
|
||||
self.assertTrue(all(sn[key] == value for key, value in
|
||||
valid_filter_opts.items()))
|
||||
self.assertLessEqual(sn['created_at'], created_before)
|
||||
self.assertGreaterEqual(sn['created_at'], created_since)
|
||||
|
||||
|
||||
class ShareNetworksTest(base.BaseSharesTest, ShareNetworkListMixin):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareNetworksTest, 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.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.create_security_service(
|
||||
ss_type='kerberos',
|
||||
**cls.data_sn_with_ldap_ss)
|
||||
|
||||
cls.sn_with_kerberos_ss = cls.create_share_network(
|
||||
cleanup_in_class=True,
|
||||
**cls.data_sn_with_kerberos_ss)
|
||||
|
||||
cls.shares_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_create_delete_share_network(self):
|
||||
# generate data for share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
# create share network
|
||||
created = self.shares_client.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, created)
|
||||
|
||||
# Delete share_network
|
||||
self.shares_client.delete_share_network(created["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_get_share_network(self):
|
||||
get = self.shares_client.get_share_network(self.sn_with_ldap_ss["id"])
|
||||
self.assertEqual('2002-02-02T00:00:00.000000', get['created_at'])
|
||||
data = self.data_sn_with_ldap_ss.copy()
|
||||
del data['created_at']
|
||||
self.assertDictContainsSubset(data, get)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_share_network(self):
|
||||
update_data = self.generate_share_network_data()
|
||||
updated = self.shares_client.update_share_network(
|
||||
self.sn_with_ldap_ss["id"],
|
||||
**update_data)
|
||||
self.assertDictContainsSubset(update_data, updated)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_update_valid_keys_sh_server_exists(self):
|
||||
self.create_share(cleanup_in_class=False)
|
||||
update_dict = {
|
||||
"name": "new_name",
|
||||
"description": "new_description",
|
||||
}
|
||||
updated = self.shares_client.update_share_network(
|
||||
self.shares_client.share_network_id, **update_dict)
|
||||
self.assertDictContainsSubset(update_dict, updated)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_recreate_share_network(self):
|
||||
# generate data for share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
# create share network
|
||||
sn1 = self.shares_client.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, sn1)
|
||||
|
||||
# Delete first share network
|
||||
self.shares_client.delete_share_network(sn1["id"])
|
||||
|
||||
# create second share network with same data
|
||||
sn2 = self.shares_client.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, sn2)
|
||||
|
||||
# Delete second share network
|
||||
self.shares_client.delete_share_network(sn2["id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_two_share_networks_with_same_net_and_subnet(self):
|
||||
# generate data for share network
|
||||
data = self.generate_share_network_data()
|
||||
|
||||
# create first share network
|
||||
sn1 = self.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, sn1)
|
||||
|
||||
# create second share network
|
||||
sn2 = self.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, sn2)
|
||||
|
||||
@testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
|
||||
"Only for setups with network creation.")
|
||||
@testtools.skipUnless(CONF.share.multitenancy_enabled,
|
||||
"Only for multitenancy.")
|
||||
@testtools.skipUnless(CONF.service_available.neutron, "Only with neutron.")
|
||||
@base.skip_if_microversion_lt("2.18")
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_gateway_with_neutron(self):
|
||||
subnet_client = self.subnets_client
|
||||
|
||||
self.create_share(cleanup_in_class=False)
|
||||
share_net_details = self.shares_v2_client.get_share_network(
|
||||
self.shares_v2_client.share_network_id)
|
||||
subnet_details = subnet_client.show_subnet(
|
||||
share_net_details['neutron_subnet_id'])
|
||||
|
||||
self.assertEqual(subnet_details['subnet']['gateway_ip'],
|
||||
share_net_details['gateway'])
|
||||
|
||||
@testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
|
||||
"Only for setups with network creation.")
|
||||
@testtools.skipUnless(CONF.share.multitenancy_enabled,
|
||||
"Only for multitenancy.")
|
||||
@testtools.skipUnless(CONF.service_available.neutron, "Only with neutron.")
|
||||
@base.skip_if_microversion_lt("2.20")
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_mtu_with_neutron(self):
|
||||
network_client = self.networks_client
|
||||
|
||||
self.create_share(cleanup_in_class=False)
|
||||
share_net_details = self.shares_v2_client.get_share_network(
|
||||
self.shares_v2_client.share_network_id)
|
||||
network_details = network_client.show_network(
|
||||
share_net_details['neutron_net_id'])
|
||||
|
||||
self.assertEqual(network_details['network']['mtu'],
|
||||
share_net_details['mtu'])
|
@ -1,134 +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 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 ShareNetworksNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_share_network_without_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share_network, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_share_network_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share_network, "wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_share_network_without_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_share_network, "")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_share_network_with_wrong_type(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_share_network, "wrong_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_nonexistant_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.update_share_network,
|
||||
"wrong_id", name="name")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_update_share_network_with_empty_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.update_share_network,
|
||||
"", name="name")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_try_update_invalid_keys_sh_server_exists(self):
|
||||
self.create_share(cleanup_in_class=False)
|
||||
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.update_share_network,
|
||||
self.shares_client.share_network_id,
|
||||
neutron_net_id="new_net_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_get_deleted_share_network(self):
|
||||
data = self.generate_share_network_data()
|
||||
sn = self.create_share_network(**data)
|
||||
self.assertDictContainsSubset(data, sn)
|
||||
|
||||
self.shares_client.delete_share_network(sn["id"])
|
||||
|
||||
# try get deleted share network entity
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_security_service,
|
||||
sn["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_share_networks_wrong_created_since_value(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.shares_client.list_share_networks_with_detail,
|
||||
params={'created_since': '2014-10-23T08:31:58.000000'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_list_share_networks_wrong_created_before_value(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.shares_client.list_share_networks_with_detail,
|
||||
params={'created_before': '2014-10-23T08:31:58.000000'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(not CONF.share.multitenancy_enabled,
|
||||
'Can run only with drivers that do handle share servers '
|
||||
'creation. Skipping.')
|
||||
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||
"This test is not suitable for pre-existing "
|
||||
"share_network.")
|
||||
def test_try_delete_share_network_with_existing_shares(self):
|
||||
# Get valid network data for successful share creation
|
||||
share_network = self.shares_client.get_share_network(
|
||||
self.shares_client.share_network_id)
|
||||
new_sn = self.create_share_network(
|
||||
neutron_net_id=share_network['neutron_net_id'],
|
||||
neutron_subnet_id=share_network['neutron_subnet_id'],
|
||||
cleanup_in_class=False)
|
||||
|
||||
# Create share with share network
|
||||
self.create_share(
|
||||
share_network_id=new_sn['id'], cleanup_in_class=False)
|
||||
|
||||
# Try delete share network
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_client.delete_share_network, new_sn['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_not_supported("2.35")
|
||||
def test_list_shares_with_like_filter_not_exist(self):
|
||||
filters = {
|
||||
'name~': 'fake_not_exist',
|
||||
'description~': 'fake_not_exist',
|
||||
}
|
||||
share_networks = (
|
||||
self.shares_v2_client.list_share_networks_with_detail(
|
||||
params=filters))
|
||||
|
||||
self.assertEqual(0, len(share_networks))
|
@ -1,64 +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 ShareTypesNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def _create_share_type(cls):
|
||||
name = data_utils.rand_name("unique_st_name")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
return cls.create_share_type(
|
||||
name, extra_specs=extra_specs,
|
||||
client=cls.admin_client)
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareTypesNegativeTest, cls).resource_setup()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
cls.st = cls._create_share_type()
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_share_type_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.create_share_type,
|
||||
data_utils.rand_name("used_user_creds"),
|
||||
client=self.shares_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_share_type_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.delete_share_type,
|
||||
self.st["share_type"]["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_add_access_to_share_type_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.add_access_to_share_type,
|
||||
self.st['share_type']['id'],
|
||||
self.shares_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_remove_access_from_share_type_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.remove_access_from_share_type,
|
||||
self.st['share_type']['id'],
|
||||
self.shares_client.tenant_id)
|
@ -1,236 +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 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 SharesNFSTest(base.BaseSharesTest):
|
||||
"""Covers share functionality, that is related to NFS share type."""
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesNFSTest, cls).resource_setup()
|
||||
if cls.protocol not in CONF.share.enable_protocols:
|
||||
message = "%s tests are disabled" % cls.protocol
|
||||
raise cls.skipException(message)
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_get_delete_share(self):
|
||||
|
||||
share = self.create_share(self.protocol)
|
||||
detailed_elements = {'name', 'id', 'availability_zone',
|
||||
'description', 'project_id',
|
||||
'created_at', 'share_proto', 'metadata',
|
||||
'size', 'snapshot_id', 'share_network_id',
|
||||
'status', 'share_type', 'volume_type', 'links',
|
||||
'is_public'}
|
||||
msg = (
|
||||
"At least one expected element missing from share "
|
||||
"response. Expected %(expected)s, got %(actual)s." % {
|
||||
"expected": detailed_elements,
|
||||
"actual": share.keys(),
|
||||
}
|
||||
)
|
||||
self.assertTrue(detailed_elements.issubset(share.keys()), msg)
|
||||
self.assertFalse(share['is_public'])
|
||||
|
||||
# The 'status' of the share returned by the create API must be
|
||||
# set and have value either 'creating' or
|
||||
# 'available' (if share creation is really fast as in
|
||||
# case of Dummy driver).
|
||||
self.assertIn(share['status'], ('creating', 'available'))
|
||||
|
||||
# Get share using v 2.1 - we expect key 'snapshot_support' to be absent
|
||||
share_get = self.shares_v2_client.get_share(share['id'], version='2.1')
|
||||
detailed_elements.add('export_location')
|
||||
self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
|
||||
|
||||
# Get share using v 2.2 - we expect key 'snapshot_support' to exist
|
||||
share_get = self.shares_v2_client.get_share(share['id'], version='2.2')
|
||||
detailed_elements.add('snapshot_support')
|
||||
self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
|
||||
|
||||
if utils.is_microversion_supported('2.9'):
|
||||
# Get share using v 2.9 - key 'export_location' is expected
|
||||
# to be absent
|
||||
share_get = self.shares_v2_client.get_share(
|
||||
share['id'], version='2.9')
|
||||
detailed_elements.remove('export_location')
|
||||
self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
|
||||
|
||||
# In v 2.11 and beyond, we expect key 'replication_type' in the
|
||||
# share data returned by the share create API.
|
||||
if utils.is_microversion_supported('2.11'):
|
||||
detailed_elements.add('replication_type')
|
||||
self.assertTrue(detailed_elements.issubset(share.keys()), msg)
|
||||
|
||||
# In v 2.16 and beyond, we add user_id in show/create/manage
|
||||
# share echo.
|
||||
if utils.is_microversion_supported('2.16'):
|
||||
detailed_elements.add('user_id')
|
||||
self.assertTrue(detailed_elements.issubset(share.keys()), msg)
|
||||
|
||||
# In v 2.24 and beyond, we add create_share_from_snapshot_support in
|
||||
# show/create/manage share echo.
|
||||
if utils.is_microversion_supported('2.24'):
|
||||
detailed_elements.add('create_share_from_snapshot_support')
|
||||
self.assertTrue(detailed_elements.issubset(share.keys()), msg)
|
||||
|
||||
# Delete share
|
||||
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'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_create_delete_snapshot(self):
|
||||
|
||||
# create snapshot
|
||||
snap = self.create_snapshot_wait_for_active(self.share["id"])
|
||||
|
||||
detailed_elements = {'name', 'id', 'description',
|
||||
'created_at', 'share_proto', 'size', 'share_size',
|
||||
'share_id', 'status', 'links'}
|
||||
msg = (
|
||||
"At least one expected element missing from share "
|
||||
"response. Expected %(expected)s, got %(actual)s." % {
|
||||
"expected": detailed_elements,
|
||||
"actual": snap.keys(),
|
||||
}
|
||||
)
|
||||
self.assertTrue(detailed_elements.issubset(snap.keys()), msg)
|
||||
|
||||
# In v2.17 and beyond, we expect user_id and project_id keys
|
||||
if utils.is_microversion_supported('2.17'):
|
||||
detailed_elements.update({'user_id', 'project_id'})
|
||||
self.assertTrue(detailed_elements.issubset(snap.keys()), msg)
|
||||
else:
|
||||
self.assertNotIn('user_id', detailed_elements)
|
||||
self.assertNotIn('project_id', detailed_elements)
|
||||
|
||||
# delete snapshot
|
||||
self.shares_client.delete_snapshot(snap["id"])
|
||||
self.shares_client.wait_for_resource_deletion(snapshot_id=snap["id"])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_snapshot, snap['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_create_share_from_snapshot(self):
|
||||
# If multitenant driver used, share_network will be provided by default
|
||||
|
||||
# create snapshot
|
||||
snap = self.create_snapshot_wait_for_active(
|
||||
self.share["id"], cleanup_in_class=False)
|
||||
|
||||
# create share from snapshot
|
||||
s2 = self.create_share(
|
||||
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
|
||||
|
||||
# The 'status' of the share returned by the create API must be
|
||||
# set and have value either 'creating' or
|
||||
# 'available' (if share creation is really fast as in
|
||||
# case of Dummy driver).
|
||||
self.assertIn(s2['status'], ('creating', 'available'))
|
||||
|
||||
# verify share, created from snapshot
|
||||
get = self.shares_client.get_share(s2["id"])
|
||||
msg = ("Expected snapshot_id %s as "
|
||||
"source of share %s" % (snap["id"], get["snapshot_id"]))
|
||||
self.assertEqual(get["snapshot_id"], snap["id"], msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipIf(not CONF.share.multitenancy_enabled,
|
||||
"Only for multitenancy.")
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_create_share_from_snapshot_share_network_not_provided(self):
|
||||
# We expect usage of share network from parent's share
|
||||
# when creating share from snapshot using a driver that supports
|
||||
# multi-tenancy.
|
||||
|
||||
# get parent share
|
||||
parent = self.shares_client.get_share(self.share["id"])
|
||||
|
||||
# create snapshot
|
||||
snap = self.create_snapshot_wait_for_active(
|
||||
self.share["id"], cleanup_in_class=False)
|
||||
|
||||
# create share from snapshot
|
||||
child = self.create_share(
|
||||
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
|
||||
|
||||
# The 'status' of the share returned by the create API must be
|
||||
# set and have value either 'creating' or
|
||||
# 'available' (if share creation is really fast as in
|
||||
# case of Dummy driver).
|
||||
self.assertIn(child['status'], ('creating', 'available'))
|
||||
|
||||
# verify share, created from snapshot
|
||||
get = self.shares_client.get_share(child["id"])
|
||||
keys = {
|
||||
"share": self.share["id"],
|
||||
"actual_sn": get["share_network_id"],
|
||||
"expected_sn": parent["share_network_id"],
|
||||
}
|
||||
msg = ("Expected share_network_id %(expected_sn)s for "
|
||||
"share %(share)s, but %(actual_sn)s found." % keys)
|
||||
self.assertEqual(
|
||||
get["share_network_id"], parent["share_network_id"], msg)
|
||||
|
||||
|
||||
class SharesCIFSTest(SharesNFSTest):
|
||||
"""Covers share functionality, that is related to CIFS share type."""
|
||||
protocol = "cifs"
|
||||
|
||||
|
||||
class SharesGLUSTERFSTest(SharesNFSTest):
|
||||
"""Covers share functionality that is related to GLUSTERFS share type."""
|
||||
protocol = "glusterfs"
|
||||
|
||||
|
||||
class SharesHDFSTest(SharesNFSTest):
|
||||
"""Covers share functionality that is related to HDFS share type."""
|
||||
protocol = "hdfs"
|
||||
|
||||
|
||||
class SharesCephFSTest(SharesNFSTest):
|
||||
"""Covers share functionality that is related to CEPHFS share type."""
|
||||
protocol = "cephfs"
|
||||
|
||||
|
||||
class SharesMapRFSTest(SharesNFSTest):
|
||||
"""Covers share functionality that is related to MapRFS share type."""
|
||||
protocol = "maprfs"
|
@ -1,723 +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
|
||||
import six
|
||||
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
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesActionsTest(base.BaseSharesTest):
|
||||
"""Covers share functionality, that doesn't related to share type."""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesActionsTest, cls).resource_setup()
|
||||
|
||||
cls.shares = []
|
||||
|
||||
# create share
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.metadata = {
|
||||
'foo_key_share_1': 'foo_value_share_1',
|
||||
'bar_key_share_1': 'foo_value_share_1',
|
||||
}
|
||||
cls.shares.append(cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
metadata=cls.metadata,
|
||||
))
|
||||
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
|
||||
cls.snap_desc = data_utils.rand_name(
|
||||
"tempest-snapshot-description")
|
||||
cls.snap = cls.create_snapshot_wait_for_active(
|
||||
cls.shares[0]["id"], cls.snap_name, cls.snap_desc)
|
||||
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
|
||||
# create second share from snapshot for purposes of sorting and
|
||||
# snapshot filtering
|
||||
cls.share_name2 = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc2 = data_utils.rand_name(
|
||||
"tempest-share-description")
|
||||
cls.metadata2 = {
|
||||
'foo_key_share_2': 'foo_value_share_2',
|
||||
'bar_key_share_2': 'foo_value_share_2',
|
||||
}
|
||||
cls.shares.append(cls.create_share(
|
||||
name=cls.share_name2,
|
||||
description=cls.share_desc2,
|
||||
metadata=cls.metadata2,
|
||||
snapshot_id=cls.snap['id'],
|
||||
))
|
||||
|
||||
def _get_share(self, version):
|
||||
|
||||
# get share
|
||||
share = self.shares_v2_client.get_share(
|
||||
self.shares[0]['id'], version=six.text_type(version))
|
||||
|
||||
# verify keys
|
||||
expected_keys = [
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "project_id", "volume_type", "share_proto", "name",
|
||||
"snapshot_id", "id", "size", "share_network_id", "metadata",
|
||||
"snapshot_id", "is_public",
|
||||
]
|
||||
if utils.is_microversion_lt(version, '2.9'):
|
||||
expected_keys.extend(["export_location", "export_locations"])
|
||||
if utils.is_microversion_ge(version, '2.2'):
|
||||
expected_keys.append("snapshot_support")
|
||||
if utils.is_microversion_ge(version, '2.5'):
|
||||
expected_keys.append("share_type_name")
|
||||
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("replication_type")
|
||||
if utils.is_microversion_ge(version, '2.16'):
|
||||
expected_keys.append("user_id")
|
||||
if utils.is_microversion_ge(version, '2.24'):
|
||||
expected_keys.append("create_share_from_snapshot_support")
|
||||
if utils.is_microversion_ge(version,
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION):
|
||||
expected_keys.append("revert_to_snapshot_support")
|
||||
actual_keys = list(share.keys())
|
||||
[self.assertIn(key, actual_keys) for key in expected_keys]
|
||||
|
||||
# verify values
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (self.share_name,
|
||||
share["name"])
|
||||
self.assertEqual(self.share_name, six.text_type(share["name"]), msg)
|
||||
|
||||
msg = ("Expected description: '%s', "
|
||||
"actual description: '%s'" % (self.share_desc,
|
||||
share["description"]))
|
||||
self.assertEqual(
|
||||
self.share_desc, six.text_type(share["description"]), msg)
|
||||
|
||||
msg = "Expected size: '%s', actual size: '%s'" % (
|
||||
CONF.share.share_size, share["size"])
|
||||
self.assertEqual(CONF.share.share_size, int(share["size"]), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_v2_1(self):
|
||||
self._get_share('2.1')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_with_snapshot_support_key(self):
|
||||
self._get_share('2.2')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.6')
|
||||
def test_get_share_with_share_type_name_key(self):
|
||||
self._get_share('2.6')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.9')
|
||||
def test_get_share_export_locations_removed(self):
|
||||
self._get_share('2.9')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.10')
|
||||
def test_get_share_with_access_rules_status(self):
|
||||
self._get_share('2.10')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.11')
|
||||
def test_get_share_with_replication_type_key(self):
|
||||
self._get_share('2.11')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.16')
|
||||
def test_get_share_with_user_id(self):
|
||||
self._get_share('2.16')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.24')
|
||||
def test_get_share_with_create_share_from_snapshot_support(self):
|
||||
self._get_share('2.24')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported(
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
def test_get_share_with_revert_to_snapshot_support(self):
|
||||
self._get_share(constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares(self):
|
||||
|
||||
# list shares
|
||||
shares = self.shares_v2_client.list_shares()
|
||||
|
||||
# verify keys
|
||||
keys = ["name", "id", "links"]
|
||||
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
for share in self.shares:
|
||||
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
def _list_shares_with_detail(self, version):
|
||||
|
||||
# list shares
|
||||
shares = self.shares_v2_client.list_shares_with_detail(
|
||||
version=six.text_type(version))
|
||||
|
||||
# verify keys
|
||||
keys = [
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "project_id", "volume_type", "share_proto", "name",
|
||||
"snapshot_id", "id", "size", "share_network_id", "metadata",
|
||||
"snapshot_id", "is_public", "share_type",
|
||||
]
|
||||
if utils.is_microversion_lt(version, '2.9'):
|
||||
keys.extend(["export_location", "export_locations"])
|
||||
if utils.is_microversion_ge(version, '2.2'):
|
||||
keys.append("snapshot_support")
|
||||
if utils.is_microversion_ge(version, '2.6'):
|
||||
keys.append("share_type_name")
|
||||
if utils.is_microversion_ge(version, '2.10'):
|
||||
keys.append("access_rules_status")
|
||||
if utils.is_microversion_ge(version, '2.11'):
|
||||
keys.append("replication_type")
|
||||
if utils.is_microversion_ge(version, '2.16'):
|
||||
keys.append("user_id")
|
||||
if utils.is_microversion_ge(version, '2.24'):
|
||||
keys.append("create_share_from_snapshot_support")
|
||||
if utils.is_microversion_ge(version,
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION):
|
||||
keys.append("revert_to_snapshot_support")
|
||||
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
|
||||
|
||||
# our shares in list and have no duplicates
|
||||
for share in self.shares:
|
||||
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_v2_1(self):
|
||||
self._list_shares_with_detail('2.1')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_and_snapshot_support_key(self):
|
||||
self._list_shares_with_detail('2.2')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.6')
|
||||
def test_list_shares_with_detail_share_type_name_key(self):
|
||||
self._list_shares_with_detail('2.6')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.9')
|
||||
def test_list_shares_with_detail_export_locations_removed(self):
|
||||
self._list_shares_with_detail('2.9')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.10')
|
||||
def test_list_shares_with_detail_with_access_rules_status(self):
|
||||
self._list_shares_with_detail('2.10')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.11')
|
||||
def test_list_shares_with_detail_replication_type_key(self):
|
||||
self._list_shares_with_detail('2.11')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported('2.16')
|
||||
def test_list_shares_with_user_id(self):
|
||||
self._list_shares_with_detail('2.16')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_and_create_share_from_snapshot_support(
|
||||
self):
|
||||
self._list_shares_with_detail('2.24')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported(
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
def test_list_shares_with_detail_with_revert_to_snapshot_support(self):
|
||||
self._list_shares_with_detail(
|
||||
constants.REVERT_TO_SNAPSHOT_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_metadata(self):
|
||||
filters = {'metadata': self.metadata}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertDictContainsSubset(
|
||||
filters['metadata'], share['metadata'])
|
||||
if CONF.share.capability_create_share_from_snapshot_support:
|
||||
self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_list_shares_with_detail_filter_by_share_network_id(self):
|
||||
base_share = self.shares_client.get_share(self.shares[0]['id'])
|
||||
filters = {'share_network_id': base_share['share_network_id']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(
|
||||
filters['share_network_id'], share['share_network_id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_list_shares_with_detail_filter_by_snapshot_id(self):
|
||||
filters = {'snapshot_id': self.snap['id']}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(filters['snapshot_id'], share['snapshot_id'])
|
||||
self.assertFalse(self.shares[0]['id'] in [s['id'] for s in shares])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_with_asc_sorting(self):
|
||||
filters = {'sort_key': 'created_at', 'sort_dir': 'asc'}
|
||||
|
||||
# list shares
|
||||
shares = self.shares_client.list_shares_with_detail(params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(shares), 0)
|
||||
sorted_list = [share['created_at'] for share in shares]
|
||||
self.assertEqual(sorted(sorted_list), sorted_list)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_existed_name(self):
|
||||
# list shares by name, at least one share is expected
|
||||
params = {"name": self.share_name}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(self.share_name, shares[0]["name"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.36")
|
||||
def test_list_shares_with_detail_filter_by_existed_description(self):
|
||||
# list shares by description, at least one share is expected
|
||||
params = {"description": self.share_desc}
|
||||
shares = self.shares_v2_client.list_shares_with_detail(params)
|
||||
self.assertEqual(self.share_name, shares[0]["name"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.36")
|
||||
def test_list_shares_with_detail_filter_by_inexact_name(self):
|
||||
# list shares by name, at least one share is expected
|
||||
params = {"name~": 'tempest-share'}
|
||||
shares = self.shares_v2_client.list_shares_with_detail(params)
|
||||
for share in shares:
|
||||
self.assertIn('tempest-share', share["name"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_fake_name(self):
|
||||
# list shares by fake name, no shares are expected
|
||||
params = {"name": data_utils.rand_name("fake-nonexistent-name")}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_active_status(self):
|
||||
# list shares by active status, at least one share is expected
|
||||
params = {"status": "available"}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertGreater(len(shares), 0)
|
||||
for share in shares:
|
||||
self.assertEqual(params["status"], share["status"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_fake_status(self):
|
||||
# list shares by fake status, no shares are expected
|
||||
params = {"status": 'fake'}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_detail_filter_by_all_tenants(self):
|
||||
# non-admin user can get shares only from his project
|
||||
params = {"all_tenants": 1}
|
||||
shares = self.shares_client.list_shares_with_detail(params)
|
||||
self.assertGreater(len(shares), 0)
|
||||
|
||||
# get share with detailed info, we need its 'project_id'
|
||||
share = self.shares_client.get_share(self.shares[0]["id"])
|
||||
project_id = share["project_id"]
|
||||
for share in shares:
|
||||
self.assertEqual(project_id, share["project_id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.42")
|
||||
def test_list_shares_with_detail_with_count(self):
|
||||
# list shares by name, at least one share is expected
|
||||
params = {"with_count": 'true'}
|
||||
shares = self.shares_v2_client.list_shares_with_detail(params)
|
||||
self.assertGreater(shares["count"], 0)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_public_with_detail(self):
|
||||
public_share = self.create_share(
|
||||
name='public_share',
|
||||
description='public_share_desc',
|
||||
is_public=True,
|
||||
cleanup_in_class=False
|
||||
)
|
||||
private_share = self.create_share(
|
||||
name='private_share',
|
||||
description='private_share_desc',
|
||||
is_public=False,
|
||||
cleanup_in_class=False
|
||||
)
|
||||
|
||||
params = {"is_public": True}
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
shares = isolated_client.list_shares_with_detail(params)
|
||||
|
||||
keys = [
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "export_location", "share_proto",
|
||||
"name", "snapshot_id", "id", "size", "project_id", "is_public",
|
||||
]
|
||||
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
|
||||
|
||||
gen = [sid["id"] for sid in shares if sid["id"] == public_share["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
self.assertFalse(any([s["id"] == private_share["id"] for s in shares]))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@ddt.data(None, '2.16', LATEST_MICROVERSION)
|
||||
def test_get_snapshot(self, version):
|
||||
|
||||
# get snapshot
|
||||
if version is None:
|
||||
snapshot = self.shares_client.get_snapshot(self.snap["id"])
|
||||
else:
|
||||
utils.skip_if_microversion_not_supported(version)
|
||||
snapshot = self.shares_v2_client.get_snapshot(
|
||||
self.snap["id"], version=version)
|
||||
|
||||
# verify keys
|
||||
expected_keys = ["status", "links", "share_id", "name",
|
||||
"share_proto", "created_at",
|
||||
"description", "id", "share_size", "size"]
|
||||
if version and utils.is_microversion_ge(version, '2.17'):
|
||||
expected_keys.extend(["user_id", "project_id"])
|
||||
actual_keys = snapshot.keys()
|
||||
|
||||
# strict key check
|
||||
self.assertEqual(set(expected_keys), set(actual_keys))
|
||||
|
||||
# verify data
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (self.snap_name,
|
||||
snapshot["name"])
|
||||
self.assertEqual(self.snap_name, snapshot["name"], msg)
|
||||
|
||||
msg = ("Expected description: '%s' actual description: '%s'" %
|
||||
(self.snap_desc, snapshot["description"]))
|
||||
self.assertEqual(self.snap_desc, snapshot["description"], msg)
|
||||
|
||||
msg = ("Expected share_id: '%s', actual share_id: '%s'" %
|
||||
(self.shares[0]["id"], snapshot["share_id"]))
|
||||
self.assertEqual(self.shares[0]["id"], snapshot["share_id"], msg)
|
||||
|
||||
# Verify that the user_id and project_id are same as the one for
|
||||
# the base share
|
||||
if version and utils.is_microversion_ge(version, '2.17'):
|
||||
msg = ("Expected %(key)s in snapshot: '%(expected)s', "
|
||||
"actual %(key)s in snapshot: '%(actual)s'")
|
||||
self.assertEqual(self.shares[0]['user_id'],
|
||||
snapshot['user_id'],
|
||||
msg % {
|
||||
'expected': self.shares[0]['user_id'],
|
||||
'actual': snapshot['user_id'],
|
||||
'key': 'user_id'})
|
||||
self.assertEqual(self.shares[0]['project_id'],
|
||||
snapshot['project_id'],
|
||||
msg % {
|
||||
'expected': self.shares[0]['project_id'],
|
||||
'actual': snapshot['project_id'],
|
||||
'key': 'project_id'})
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots(self):
|
||||
|
||||
# list share snapshots
|
||||
snaps = self.shares_client.list_snapshots()
|
||||
|
||||
# verify keys
|
||||
keys = ["id", "name", "links"]
|
||||
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@ddt.data(None, '2.16', '2.36', LATEST_MICROVERSION)
|
||||
def test_list_snapshots_with_detail(self, version):
|
||||
params = None
|
||||
if version and utils.is_microversion_ge(version, '2.36'):
|
||||
params = {'name~': 'tempest', 'description~': 'tempest'}
|
||||
# list share snapshots
|
||||
if version is None:
|
||||
snaps = self.shares_client.list_snapshots_with_detail()
|
||||
else:
|
||||
utils.skip_if_microversion_not_supported(version)
|
||||
snaps = self.shares_v2_client.list_snapshots_with_detail(
|
||||
version=version, params=params)
|
||||
|
||||
# verify keys
|
||||
expected_keys = ["status", "links", "share_id", "name",
|
||||
"share_proto", "created_at", "description", "id",
|
||||
"share_size", "size"]
|
||||
if version and utils.is_microversion_ge(version, '2.17'):
|
||||
expected_keys.extend(["user_id", "project_id"])
|
||||
|
||||
# strict key check
|
||||
[self.assertEqual(set(expected_keys), set(s.keys())) for s in snaps]
|
||||
|
||||
# our share id in list and have no duplicates
|
||||
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
|
||||
msg = "expected id lists %s times in share list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots_with_detail_use_limit(self):
|
||||
for l, o in [('1', '1'), ('0', '1')]:
|
||||
filters = {
|
||||
'limit': l,
|
||||
'offset': o,
|
||||
'share_id': self.shares[0]['id'],
|
||||
}
|
||||
|
||||
# list snapshots
|
||||
snaps = self.shares_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
# Our snapshot should not be listed
|
||||
self.assertEqual(0, len(snaps))
|
||||
|
||||
# Only our one snapshot should be listed
|
||||
snaps = self.shares_client.list_snapshots_with_detail(
|
||||
params={'limit': '1', 'offset': '0',
|
||||
'share_id': self.shares[0]['id']})
|
||||
|
||||
self.assertEqual(1, len(snaps['snapshots']))
|
||||
self.assertEqual(self.snap['id'], snaps['snapshots'][0]['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots_with_detail_filter_by_status_and_name(self):
|
||||
filters = {'status': 'available', 'name': self.snap_name}
|
||||
|
||||
# list snapshots
|
||||
snaps = self.shares_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(snaps), 0)
|
||||
for snap in snaps:
|
||||
self.assertEqual(filters['status'], snap['status'])
|
||||
self.assertEqual(filters['name'], snap['name'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@base.skip_if_microversion_not_supported("2.35")
|
||||
def test_list_snapshots_with_detail_filter_by_description(self):
|
||||
filters = {'description': self.snap_desc}
|
||||
|
||||
# list snapshots
|
||||
snaps = self.shares_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(snaps), 0)
|
||||
for snap in snaps:
|
||||
self.assertEqual(filters['description'], snap['description'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_list_snapshots_with_detail_and_asc_sorting(self):
|
||||
filters = {'sort_key': 'share_id', 'sort_dir': 'asc'}
|
||||
|
||||
# list snapshots
|
||||
snaps = self.shares_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
# verify response
|
||||
self.assertGreater(len(snaps), 0)
|
||||
sorted_list = [snap['share_id'] for snap in snaps]
|
||||
self.assertEqual(sorted(sorted_list), sorted_list)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_extend_tests,
|
||||
"Share extend tests are disabled.")
|
||||
def test_extend_share(self):
|
||||
share = self.create_share(cleanup_in_class=False)
|
||||
new_size = int(share['size']) + 1
|
||||
|
||||
# extend share and wait for active status
|
||||
self.shares_v2_client.extend_share(share['id'], new_size)
|
||||
self.shares_client.wait_for_share_status(share['id'], 'available')
|
||||
|
||||
# check state and new size
|
||||
share_get = self.shares_v2_client.get_share(share['id'])
|
||||
msg = (
|
||||
"Share could not be extended. "
|
||||
"Expected %(expected)s, got %(actual)s." % {
|
||||
"expected": new_size,
|
||||
"actual": share_get['size'],
|
||||
}
|
||||
)
|
||||
self.assertEqual(new_size, share_get['size'], msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_shrink_tests,
|
||||
"Share shrink tests are disabled.")
|
||||
def test_shrink_share(self):
|
||||
size = CONF.share.share_size + 1
|
||||
share = self.create_share(size=size, cleanup_in_class=False)
|
||||
new_size = int(share['size']) - 1
|
||||
|
||||
# shrink share and wait for active status
|
||||
self.shares_v2_client.shrink_share(share['id'], new_size)
|
||||
self.shares_client.wait_for_share_status(share['id'], 'available')
|
||||
|
||||
# check state and new size
|
||||
share_get = self.shares_v2_client.get_share(share['id'])
|
||||
msg = (
|
||||
"Share could not be shrunk. "
|
||||
"Expected %(expected)s, got %(actual)s." % {
|
||||
"expected": new_size,
|
||||
"actual": share_get['size'],
|
||||
}
|
||||
)
|
||||
self.assertEqual(new_size, share_get['size'], msg)
|
||||
|
||||
|
||||
class SharesRenameTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesRenameTest, cls).resource_setup()
|
||||
|
||||
# create share
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name, description=cls.share_desc)
|
||||
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
|
||||
cls.snap_desc = data_utils.rand_name(
|
||||
"tempest-snapshot-description")
|
||||
cls.snap = cls.create_snapshot_wait_for_active(
|
||||
cls.share["id"], cls.snap_name, cls.snap_desc)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_share(self):
|
||||
|
||||
# get share
|
||||
share = self.shares_client.get_share(self.share['id'])
|
||||
self.assertEqual(self.share_name, share["name"])
|
||||
self.assertEqual(self.share_desc, share["description"])
|
||||
self.assertFalse(share["is_public"])
|
||||
|
||||
# update share
|
||||
new_name = data_utils.rand_name("tempest-new-name")
|
||||
new_desc = data_utils.rand_name("tempest-new-description")
|
||||
updated = self.shares_client.update_share(
|
||||
share["id"], new_name, new_desc, is_public=True)
|
||||
self.assertEqual(new_name, updated["name"])
|
||||
self.assertEqual(new_desc, updated["description"])
|
||||
self.assertTrue(updated["is_public"])
|
||||
|
||||
# get share
|
||||
share = self.shares_client.get_share(self.share['id'])
|
||||
self.assertEqual(new_name, share["name"])
|
||||
self.assertEqual(new_desc, share["description"])
|
||||
self.assertTrue(share["is_public"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_rename_snapshot(self):
|
||||
|
||||
# get snapshot
|
||||
get = self.shares_client.get_snapshot(self.snap["id"])
|
||||
self.assertEqual(self.snap_name, get["name"])
|
||||
self.assertEqual(self.snap_desc, get["description"])
|
||||
|
||||
# rename snapshot
|
||||
new_name = data_utils.rand_name("tempest-new-name-for-snapshot")
|
||||
new_desc = data_utils.rand_name("tempest-new-description-for-snapshot")
|
||||
renamed = self.shares_client.rename_snapshot(
|
||||
self.snap["id"], new_name, new_desc)
|
||||
self.assertEqual(new_name, renamed["name"])
|
||||
self.assertEqual(new_desc, renamed["description"])
|
||||
|
||||
# get snapshot
|
||||
get = self.shares_client.get_snapshot(self.snap["id"])
|
||||
self.assertEqual(new_name, get["name"])
|
||||
self.assertEqual(new_desc, get["description"])
|
@ -1,245 +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 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
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesActionsNegativeTest(base.BaseSharesMixedTest):
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesActionsNegativeTest, cls).resource_setup()
|
||||
cls.admin_client = cls.admin_shares_v2_client
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc)
|
||||
if CONF.share.run_snapshot_tests:
|
||||
# create snapshot
|
||||
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
|
||||
cls.snap_desc = data_utils.rand_name(
|
||||
"tempest-snapshot-description")
|
||||
cls.snap = cls.create_snapshot_wait_for_active(
|
||||
cls.share["id"], cls.snap_name, cls.snap_desc)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_extend_tests,
|
||||
"Share extend tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_quota_tests,
|
||||
"Quota tests are disabled.")
|
||||
def test_share_extend_over_quota(self):
|
||||
tenant_quotas = self.shares_client.show_quotas(
|
||||
self.shares_client.tenant_id)
|
||||
new_size = int(tenant_quotas["gigabytes"]) + 1
|
||||
|
||||
# extend share with over quota and check result
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.extend_share,
|
||||
self.share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_extend_tests,
|
||||
"Share extend tests are disabled.")
|
||||
def test_share_extend_with_less_size(self):
|
||||
new_size = int(self.share['size']) - 1
|
||||
|
||||
# extend share with invalid size and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.extend_share,
|
||||
self.share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_extend_tests,
|
||||
"Share extend tests are disabled.")
|
||||
def test_share_extend_with_same_size(self):
|
||||
new_size = int(self.share['size'])
|
||||
|
||||
# extend share with invalid size and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.extend_share,
|
||||
self.share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_extend_tests,
|
||||
"Share extend tests are disabled.")
|
||||
def test_share_extend_with_invalid_share_state(self):
|
||||
share = self.create_share(cleanup_in_class=False)
|
||||
new_size = int(share['size']) + 1
|
||||
|
||||
# set "error" state
|
||||
self.admin_client.reset_state(share['id'])
|
||||
|
||||
# run extend operation on same share and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.extend_share,
|
||||
share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_shrink_tests,
|
||||
"Share shrink tests are disabled.")
|
||||
def test_share_shrink_with_greater_size(self):
|
||||
new_size = int(self.share['size']) + 1
|
||||
|
||||
# shrink share with invalid size and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.shrink_share,
|
||||
self.share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_shrink_tests,
|
||||
"Share shrink tests are disabled.")
|
||||
def test_share_shrink_with_same_size(self):
|
||||
new_size = int(self.share['size'])
|
||||
|
||||
# shrink share with invalid size and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.shrink_share,
|
||||
self.share['id'],
|
||||
new_size)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_shrink_tests,
|
||||
"Share shrink tests are disabled.")
|
||||
def test_share_shrink_with_invalid_share_state(self):
|
||||
size = CONF.share.share_size + 1
|
||||
share = self.create_share(size=size, cleanup_in_class=False)
|
||||
new_size = int(share['size']) - 1
|
||||
|
||||
# set "error" state
|
||||
self.admin_client.reset_state(share['id'])
|
||||
|
||||
# run shrink operation on same share and check result
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.shrink_share,
|
||||
share['id'],
|
||||
new_size)
|
||||
|
||||
@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_shares_with_export_location_and_invalid_version(
|
||||
self, export_location_type):
|
||||
# In API versions <v2.35, querying the share 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',
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
params=filters, version="2.34")
|
||||
|
||||
self.assertGreater(len(shares), 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_shares_with_export_location_not_exist(
|
||||
self, export_location_type):
|
||||
filters = {
|
||||
'export_location_' + export_location_type: 'fake_not_exist',
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_not_supported("2.36")
|
||||
def test_list_shares_with_like_filter_and_invalid_version(self):
|
||||
# In API versions < v2.36, querying the share API by inexact
|
||||
# filter (name or description) should have no effect. Those
|
||||
# filters were supported from v2.36
|
||||
filters = {
|
||||
'name~': 'fake',
|
||||
'description~': 'fake',
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
params=filters, version="2.35")
|
||||
|
||||
self.assertGreater(len(shares), 0)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_not_supported("2.36")
|
||||
def test_list_shares_with_like_filter_not_exist(self):
|
||||
filters = {
|
||||
'name~': 'fake_not_exist',
|
||||
'description~': 'fake_not_exist',
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_shares_with_name_not_exist(self):
|
||||
filters = {
|
||||
'name': "tempest-share",
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_not_supported("2.36")
|
||||
def test_list_shares_with_description_not_exist(self):
|
||||
filters = {
|
||||
'description': "tempest-share",
|
||||
}
|
||||
shares = self.shares_v2_client.list_shares(params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@base.skip_if_microversion_not_supported("2.36")
|
||||
def test_list_snapshots_with_description_not_exist(self):
|
||||
filters = {
|
||||
'description': "tempest-snapshot",
|
||||
}
|
||||
shares = self.shares_v2_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_snapshots_with_name_not_exist(self):
|
||||
filters = {
|
||||
'name': "tempest-snapshot",
|
||||
}
|
||||
shares = self.shares_v2_client.list_snapshots_with_detail(
|
||||
params=filters)
|
||||
|
||||
self.assertEqual(0, len(shares))
|
@ -1,283 +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 import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests import share_exceptions
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class SharesNegativeTest(base.BaseSharesTest):
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesNegativeTest, cls).resource_setup()
|
||||
cls.share = cls.create_share(
|
||||
name='public_share',
|
||||
description='public_share_desc',
|
||||
is_public=True,
|
||||
metadata={'key': 'value'}
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_share_with_wrong_public_value(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.update_share, self.share["id"],
|
||||
is_public="truebar")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_try_delete_share_with_existing_snapshot(self):
|
||||
# share can not be deleted while snapshot exists
|
||||
|
||||
# create share
|
||||
share = self.create_share()
|
||||
|
||||
# create snapshot
|
||||
self.create_snapshot_wait_for_active(share["id"])
|
||||
|
||||
# try delete share
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.delete_share, share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_create_share_from_snap_with_less_size(self):
|
||||
# requires minimum 5Gb available space
|
||||
|
||||
skip_msg = "Check disc space for this test"
|
||||
|
||||
try: # create share
|
||||
size = CONF.share.share_size + 1
|
||||
share = self.create_share(size=size, cleanup_in_class=False)
|
||||
except share_exceptions.ShareBuildErrorException:
|
||||
self.skip(skip_msg)
|
||||
|
||||
try: # create snapshot
|
||||
snap = self.create_snapshot_wait_for_active(
|
||||
share["id"], cleanup_in_class=False)
|
||||
except share_exceptions.SnapshotBuildErrorException:
|
||||
self.skip(skip_msg)
|
||||
|
||||
# try create share from snapshot with less size
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_share,
|
||||
snapshot_id=snap["id"],
|
||||
cleanup_in_class=False)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(not CONF.share.multitenancy_enabled,
|
||||
"Only for multitenancy.")
|
||||
def test_create_share_with_nonexistant_share_network(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.create_share,
|
||||
share_network_id="wrong_sn_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(not CONF.share.multitenancy_enabled,
|
||||
"Only for multitenancy.")
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
@testtools.skipUnless(
|
||||
CONF.share.capability_create_share_from_snapshot_support,
|
||||
"Create share from snapshot tests are disabled.")
|
||||
def test_create_share_from_snap_with_different_share_network(self):
|
||||
# We can't create a share from a snapshot whose base share does not
|
||||
# have 'create_share_from_snapshot_support'.
|
||||
|
||||
# create share
|
||||
share = self.create_share(cleanup_in_class=False)
|
||||
|
||||
# get parent's share network
|
||||
parent_share = self.shares_client.get_share(share["id"])
|
||||
parent_sn = self.shares_client.get_share_network(
|
||||
parent_share["share_network_id"])
|
||||
|
||||
# create new share-network - net duplicate of parent's share
|
||||
new_duplicated_sn = self.create_share_network(
|
||||
cleanup_in_class=False,
|
||||
neutron_net_id=parent_sn["neutron_net_id"],
|
||||
neutron_subnet_id=parent_sn["neutron_subnet_id"],
|
||||
)
|
||||
|
||||
# create snapshot of parent share
|
||||
snap = self.create_snapshot_wait_for_active(
|
||||
share["id"], cleanup_in_class=False)
|
||||
|
||||
# try create share with snapshot using another share-network
|
||||
# 400 bad request is expected
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share,
|
||||
cleanup_in_class=False,
|
||||
share_network_id=new_duplicated_sn["id"],
|
||||
snapshot_id=snap["id"],
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_other_tenants_public_share(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
self.assertRaises(lib_exc.Forbidden, isolated_client.update_share,
|
||||
self.share["id"], name="new_name")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_other_tenants_public_share(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
isolated_client.delete_share,
|
||||
self.share['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_set_metadata_of_other_tenants_public_share(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
isolated_client.set_metadata,
|
||||
self.share['id'],
|
||||
{'key': 'value'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_metadata_of_other_tenants_public_share(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
isolated_client.update_all_metadata,
|
||||
self.share['id'],
|
||||
{'key': 'value'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_metadata_of_other_tenants_public_share(self):
|
||||
isolated_client = self.get_client_with_isolated_creds(
|
||||
type_of_creds='alt')
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
isolated_client.delete_metadata,
|
||||
self.share['id'],
|
||||
'key')
|
||||
|
||||
|
||||
class SharesAPIOnlyNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_unmanage_share_by_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.unmanage_share,
|
||||
'fake-id')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_manage_share_by_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.manage_share,
|
||||
'fake-host', 'nfs', '/export/path',
|
||||
'fake-type')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_by_user_with_host_filter(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_v2_client.list_shares,
|
||||
params={'host': 'fake_host'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_by_share_server_by_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.list_shares,
|
||||
params={'share_server_id': 12345})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_non_existent_az(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.create_share,
|
||||
availability_zone='fake_az')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_zero_size(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_share, size=0)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_invalid_size(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_share, size="#$%")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_out_passing_size(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_share, size="")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_delete_snapshot_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_snapshot,
|
||||
"wrong_share_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_create_snapshot_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.create_snapshot,
|
||||
"wrong_share_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_invalid_protocol(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_share,
|
||||
share_protocol="nonexistent_protocol")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_wrong_public_value(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_client.create_share, is_public='truebar')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_share_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound, self.shares_client.get_share,
|
||||
"wrong_share_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_share_without_passing_share_id(self):
|
||||
# Should not be able to get share when empty ID is passed
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share, '')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_list_shares_nonadmin_with_nonexistent_share_server_filter(self):
|
||||
# filtering by share server allowed only for admins by default
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.list_shares_with_detail,
|
||||
{'share_server_id': 'fake_share_server_id'})
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_share_with_wrong_id(self):
|
||||
self.assertRaises(lib_exc.NotFound, self.shares_client.delete_share,
|
||||
"wrong_share_id")
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_share_without_passing_share_id(self):
|
||||
# Should not be able to delete share when empty ID is passed
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.delete_share, '')
|
@ -1,101 +0,0 @@
|
||||
# Copyright 2016 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 six
|
||||
|
||||
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
|
||||
|
||||
|
||||
class BaseShareSnapshotRulesTest(base.BaseSharesTest):
|
||||
|
||||
protocol = ""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(BaseShareSnapshotRulesTest, cls).resource_setup()
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.snapshot = cls.create_snapshot_wait_for_active(cls.share['id'])
|
||||
|
||||
def _test_create_delete_access_rules(self, access_to):
|
||||
# create rule
|
||||
rule = self.shares_v2_client.create_snapshot_access_rule(
|
||||
self.snapshot['id'], self.access_type, access_to)
|
||||
|
||||
for key in ('deleted', 'deleted_at', 'instance_mappings'):
|
||||
self.assertNotIn(key, list(six.iterkeys(rule)))
|
||||
|
||||
self.shares_v2_client.wait_for_snapshot_access_rule_status(
|
||||
self.snapshot['id'], rule['id'])
|
||||
|
||||
# delete rule and wait for deletion
|
||||
self.shares_v2_client.delete_snapshot_access_rule(self.snapshot['id'],
|
||||
rule['id'])
|
||||
self.shares_v2_client.wait_for_snapshot_access_rule_deletion(
|
||||
self.snapshot['id'], rule['id'])
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests and
|
||||
CONF.share.run_snapshot_tests,
|
||||
'Mountable snapshots tests are disabled.')
|
||||
@ddt.ddt
|
||||
class ShareSnapshotIpRulesForNFSTest(BaseShareSnapshotRulesTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_ip_rules_for_protocols):
|
||||
msg = "IP rule tests for %s protocol are disabled." % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
super(ShareSnapshotIpRulesForNFSTest, cls).resource_setup()
|
||||
|
||||
cls.access_type = "ip"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@ddt.data("1.1.1.1", "1.2.3.4/32")
|
||||
def test_create_delete_access_rules(self, access_to):
|
||||
self._test_create_delete_access_rules(access_to)
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests,
|
||||
'Mountable snapshots tests are disabled.')
|
||||
@ddt.ddt
|
||||
class ShareSnapshotUserRulesForCIFSTest(BaseShareSnapshotRulesTest):
|
||||
protocol = "cifs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_user_rules_for_protocols):
|
||||
msg = ("User rule tests for %s protocol are "
|
||||
"disabled." % cls.protocol)
|
||||
raise cls.skipException(msg)
|
||||
super(ShareSnapshotUserRulesForCIFSTest, cls).resource_setup()
|
||||
|
||||
cls.access_type = "user"
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_delete_access_rules(self):
|
||||
access_to = CONF.share.username_for_user_rules
|
||||
self._test_create_delete_access_rules(access_to)
|
@ -1,90 +0,0 @@
|
||||
# Copyright 2016 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 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.tests.api import test_snapshot_rules
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests and
|
||||
CONF.share.run_snapshot_tests,
|
||||
'Mountable snapshots tests are disabled.')
|
||||
@ddt.ddt
|
||||
class SnapshotIpRulesForNFSNegativeTest(
|
||||
test_snapshot_rules.BaseShareSnapshotRulesTest):
|
||||
protocol = "nfs"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
if not (cls.protocol in CONF.share.enable_protocols and
|
||||
cls.protocol in CONF.share.enable_ip_rules_for_protocols):
|
||||
msg = "IP rule tests for %s protocol are disabled." % cls.protocol
|
||||
raise cls.skipException(msg)
|
||||
super(SnapshotIpRulesForNFSNegativeTest, cls).resource_setup()
|
||||
|
||||
# create share
|
||||
cls.share = cls.create_share(cls.protocol)
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data("1.2.3.256", "1.1.1.-", "1.2.3.4/33", "1.2.3.*", "1.2.3.*/23",
|
||||
"1.2.3.1|23", "1.2.3.1/", "1.2.3.1/-1",
|
||||
"fe80:217:f2ff:fe07:ed62", "2001:db8::1/148",
|
||||
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||
"2001:0db8:0000:85a3:0000:0000:ac1f:8001/64")
|
||||
def test_create_access_rule_ip_with_wrong_target(self, target):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.create_snapshot_access_rule,
|
||||
self.snap["id"], "ip", target)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_duplicate_of_ip_rule(self):
|
||||
self._test_duplicate_rules()
|
||||
self._test_duplicate_rules()
|
||||
|
||||
def _test_duplicate_rules(self):
|
||||
# test data
|
||||
access_type = "ip"
|
||||
access_to = "1.2.3.4"
|
||||
|
||||
# create rule
|
||||
rule = self.shares_v2_client.create_snapshot_access_rule(
|
||||
self.snap['id'], access_type, access_to)
|
||||
|
||||
self.shares_v2_client.wait_for_snapshot_access_rule_status(
|
||||
self.snap['id'], rule['id'])
|
||||
|
||||
# try create duplicate of rule
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.shares_v2_client.create_snapshot_access_rule,
|
||||
self.snap["id"], access_type, access_to)
|
||||
|
||||
# delete rule and wait for deletion
|
||||
self.shares_v2_client.delete_snapshot_access_rule(self.snap['id'],
|
||||
rule['id'])
|
||||
self.shares_v2_client.wait_for_snapshot_access_rule_deletion(
|
||||
self.snap['id'], rule['id'])
|
||||
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_snapshot_access_rule,
|
||||
self.snap['id'], rule['id'])
|
File diff suppressed because it is too large
Load Diff
@ -1,253 +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.
|
||||
|
||||
from oslo_log import log
|
||||
import six
|
||||
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.common import remote_client
|
||||
from manila_tempest_tests.tests.scenario import manager
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ShareScenarioTest(manager.NetworkScenarioTest):
|
||||
"""Provide harness to do Manila scenario tests."""
|
||||
|
||||
credentials = ('admin', 'primary')
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareScenarioTest, cls).resource_setup()
|
||||
|
||||
# Manila clients
|
||||
cls.shares_client = cls.os_primary.share_v1.SharesClient()
|
||||
cls.shares_v2_client = cls.os_primary.share_v2.SharesV2Client()
|
||||
cls.shares_admin_client = cls.os_admin.share_v1.SharesClient()
|
||||
cls.shares_admin_v2_client = cls.os_admin.share_v2.SharesV2Client()
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(ShareScenarioTest, cls).skip_checks()
|
||||
if not CONF.service_available.manila:
|
||||
raise cls.skipException("Manila support is required")
|
||||
|
||||
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,
|
||||
client=None, cleanup_in_class=True):
|
||||
"""Create a share
|
||||
|
||||
:param share_protocol: NFS or CIFS
|
||||
:param size: size in GB
|
||||
:param name: name of the share (otherwise random)
|
||||
:param snapshot_id: snapshot as basis for the share
|
||||
:param description: description of the share
|
||||
:param metadata: adds additional metadata
|
||||
:param share_network_id: id of network to be used
|
||||
:param share_type_id: type of the share to be created
|
||||
:param client: client object
|
||||
:param cleanup_in_class: default: True
|
||||
:returns: a created share
|
||||
"""
|
||||
client = client or self.shares_client
|
||||
description = description or "Tempest's share"
|
||||
if not name:
|
||||
name = data_utils.rand_name("manila-scenario")
|
||||
if CONF.share.multitenancy_enabled:
|
||||
share_network_id = (share_network_id or client.share_network_id)
|
||||
else:
|
||||
share_network_id = None
|
||||
metadata = metadata or {}
|
||||
kwargs = {
|
||||
'share_protocol': share_protocol,
|
||||
'size': size or CONF.share.share_size,
|
||||
'name': name,
|
||||
'snapshot_id': snapshot_id,
|
||||
'description': description,
|
||||
'metadata': metadata,
|
||||
'share_network_id': share_network_id,
|
||||
'share_type_id': share_type_id,
|
||||
}
|
||||
share = self.shares_client.create_share(**kwargs)
|
||||
|
||||
self.addCleanup(client.wait_for_resource_deletion,
|
||||
share_id=share['id'])
|
||||
self.addCleanup(client.delete_share,
|
||||
share['id'])
|
||||
|
||||
client.wait_for_share_status(share['id'], 'available')
|
||||
return share
|
||||
|
||||
def _create_snapshot(self, share_id, client=None, **kwargs):
|
||||
client = client or self.shares_v2_client
|
||||
snapshot = client.create_snapshot(share_id, **kwargs)
|
||||
self.addCleanup(
|
||||
client.wait_for_resource_deletion, snapshot_id=snapshot['id'])
|
||||
self.addCleanup(client.delete_snapshot, snapshot['id'])
|
||||
client.wait_for_snapshot_status(snapshot["id"], "available")
|
||||
return snapshot
|
||||
|
||||
def _wait_for_share_server_deletion(self, sn_id, client=None):
|
||||
"""Wait for a share server to be deleted
|
||||
|
||||
:param sn_id: shared network id
|
||||
:param client: client object
|
||||
"""
|
||||
client = client or self.shares_admin_client
|
||||
servers = client.list_share_servers(
|
||||
search_opts={"share_network": sn_id})
|
||||
for server in servers:
|
||||
client.delete_share_server(server['id'])
|
||||
for server in servers:
|
||||
client.wait_for_resource_deletion(server_id=server['id'])
|
||||
|
||||
def _create_share_network(self, client=None, **kwargs):
|
||||
"""Create a share network
|
||||
|
||||
:param client: client object
|
||||
:returns: a created share network
|
||||
"""
|
||||
|
||||
client = client or self.shares_client
|
||||
sn = client.create_share_network(**kwargs)
|
||||
|
||||
self.addCleanup(client.wait_for_resource_deletion,
|
||||
sn_id=sn['id'])
|
||||
self.addCleanup(client.delete_share_network,
|
||||
sn['id'])
|
||||
self.addCleanup(self._wait_for_share_server_deletion,
|
||||
sn['id'])
|
||||
return sn
|
||||
|
||||
def _allow_access(self, share_id, client=None,
|
||||
access_type="ip", access_to="0.0.0.0", cleanup=True):
|
||||
"""Allow share access
|
||||
|
||||
:param share_id: id of the share
|
||||
:param client: client object
|
||||
:param access_type: "ip", "user" or "cert"
|
||||
:param access_to
|
||||
:returns: access object
|
||||
"""
|
||||
client = client or self.shares_client
|
||||
access = client.create_access_rule(share_id, access_type, access_to)
|
||||
|
||||
# NOTE(u_glide): Ignore provided client, because we always need v2
|
||||
# client to make this call
|
||||
self.shares_v2_client.wait_for_share_status(
|
||||
share_id, "active", status_attr='access_rules_status')
|
||||
|
||||
if cleanup:
|
||||
self.addCleanup(client.delete_access_rule, share_id, access['id'])
|
||||
return access
|
||||
|
||||
def _allow_access_snapshot(self, snapshot_id, access_type="ip",
|
||||
access_to="0.0.0.0/0", cleanup=True):
|
||||
"""Allow snapshot access
|
||||
|
||||
:param snapshot_id: id of the snapshot
|
||||
:param access_type: "ip", "user" or "cert"
|
||||
:param access_to
|
||||
:returns: access object
|
||||
"""
|
||||
access = self.shares_v2_client.create_snapshot_access_rule(
|
||||
snapshot_id, access_type, access_to)
|
||||
|
||||
if cleanup:
|
||||
self.addCleanup(self.shares_v2_client.delete_snapshot_access_rule,
|
||||
snapshot_id, access['id'])
|
||||
|
||||
self.shares_v2_client.wait_for_snapshot_access_rule_status(
|
||||
snapshot_id, access['id'])
|
||||
|
||||
return access
|
||||
|
||||
def _create_router_interface(self, subnet_id, client=None, router_id=None):
|
||||
"""Create a router interface
|
||||
|
||||
:param subnet_id: id of the subnet
|
||||
:param client: client object
|
||||
"""
|
||||
if not client:
|
||||
client = self.routers_client
|
||||
if not router_id:
|
||||
router_id = self._get_router()['id']
|
||||
client.add_router_interface(router_id, subnet_id=subnet_id)
|
||||
self.addCleanup(
|
||||
client.remove_router_interface, router_id, subnet_id=subnet_id)
|
||||
|
||||
def get_remote_client(self, *args, **kwargs):
|
||||
if not CONF.share.image_with_share_tools:
|
||||
return super(ShareScenarioTest,
|
||||
self).get_remote_client(*args, **kwargs)
|
||||
# NOTE(u_glide): We need custom implementation of this method until
|
||||
# original implementation depends on CONF.compute.ssh_auth_method
|
||||
# option.
|
||||
server_or_ip = kwargs['server_or_ip']
|
||||
if isinstance(server_or_ip, six.string_types):
|
||||
ip = server_or_ip
|
||||
else:
|
||||
addr = server_or_ip['addresses'][
|
||||
CONF.validation.network_for_ssh][0]
|
||||
ip = addr['addr']
|
||||
|
||||
# NOTE(u_glide): Both options (pkey and password) are required here to
|
||||
# support service images without Nova metadata support
|
||||
client_params = {
|
||||
'username': kwargs['username'],
|
||||
'password': CONF.share.image_password,
|
||||
'pkey': kwargs.get('private_key'),
|
||||
}
|
||||
|
||||
linux_client = remote_client.RemoteClient(ip, **client_params)
|
||||
try:
|
||||
linux_client.validate_authentication()
|
||||
except Exception:
|
||||
LOG.exception('Initializing SSH connection to %s failed', ip)
|
||||
self._log_console_output()
|
||||
raise
|
||||
|
||||
return linux_client
|
||||
|
||||
def _migrate_share(self, share_id, dest_host, status, force_host_assisted,
|
||||
client=None):
|
||||
client = client or self.shares_admin_v2_client
|
||||
client.migrate_share(
|
||||
share_id, dest_host, writable=False, preserve_metadata=False,
|
||||
nondisruptive=False, preserve_snapshots=False,
|
||||
force_host_assisted_migration=force_host_assisted)
|
||||
share = client.wait_for_migration_status(share_id, dest_host, status)
|
||||
return share
|
||||
|
||||
def _migration_complete(self, share_id, dest_host, client=None, **kwargs):
|
||||
client = client or self.shares_admin_v2_client
|
||||
client.migration_complete(share_id, **kwargs)
|
||||
share = client.wait_for_migration_status(
|
||||
share_id, dest_host, constants.TASK_STATE_MIGRATION_SUCCESS,
|
||||
**kwargs)
|
||||
return share
|
||||
|
||||
def _create_share_type(self, name, is_public=True, **kwargs):
|
||||
share_type = self.shares_admin_v2_client.create_share_type(name,
|
||||
is_public,
|
||||
**kwargs)
|
||||
self.addCleanup(self.shares_admin_v2_client.delete_share_type,
|
||||
share_type['share_type']['id'])
|
||||
return share_type
|
@ -1,594 +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 ddt
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import exceptions
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
from manila_tempest_tests.tests.scenario import manager_share as manager
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
|
||||
"""This smoke test case follows this basic set of operations:
|
||||
|
||||
* Create share network
|
||||
* Create share
|
||||
* Launch an instance
|
||||
* Allow access
|
||||
* Perform ssh to instance
|
||||
* Mount share
|
||||
* Terminate the instance
|
||||
"""
|
||||
protocol = None
|
||||
|
||||
def setUp(self):
|
||||
super(ShareBasicOpsBase, self).setUp()
|
||||
base.verify_test_has_appropriate_tags(self)
|
||||
self.image_ref = None
|
||||
# Setup image and flavor the test instance
|
||||
# Support both configured and injected values
|
||||
self.floatings = {}
|
||||
if self.protocol not in CONF.share.enable_protocols:
|
||||
message = "%s tests are disabled" % self.protocol
|
||||
raise self.skipException(message)
|
||||
if self.protocol not in CONF.share.enable_ip_rules_for_protocols:
|
||||
message = ("%s tests for access rules other than IP are disabled" %
|
||||
self.protocol)
|
||||
raise self.skipException(message)
|
||||
if not hasattr(self, 'flavor_ref'):
|
||||
self.flavor_ref = CONF.share.client_vm_flavor_ref
|
||||
if CONF.share.image_with_share_tools:
|
||||
images = self.compute_images_client.list_images()["images"]
|
||||
for img in images:
|
||||
if img["name"] == CONF.share.image_with_share_tools:
|
||||
self.image_ref = img['id']
|
||||
break
|
||||
if not self.image_ref:
|
||||
msg = ("Image %s not found" %
|
||||
CONF.share.image_with_share_tools)
|
||||
raise exceptions.InvalidConfiguration(message=msg)
|
||||
self.ssh_user = CONF.share.image_username
|
||||
LOG.debug('Starting test for i:{image}, f:{flavor}. '
|
||||
'user: {ssh_user}'.format(
|
||||
image=self.image_ref, flavor=self.flavor_ref,
|
||||
ssh_user=self.ssh_user))
|
||||
self.security_group = self._create_security_group()
|
||||
self.create_share_network()
|
||||
|
||||
def boot_instance(self, wait_until="ACTIVE"):
|
||||
self.keypair = self.create_keypair()
|
||||
security_groups = [{'name': self.security_group['name']}]
|
||||
create_kwargs = {
|
||||
'key_name': self.keypair['name'],
|
||||
'security_groups': security_groups,
|
||||
'wait_until': wait_until,
|
||||
}
|
||||
if CONF.share.multitenancy_enabled:
|
||||
create_kwargs['networks'] = [{'uuid': self.net['id']}, ]
|
||||
instance = self.create_server(
|
||||
image_id=self.image_ref, flavor=self.flavor_ref, **create_kwargs)
|
||||
return instance
|
||||
|
||||
def init_ssh(self, instance, do_ping=False):
|
||||
# Obtain a floating IP
|
||||
floating_ip = (self.compute_floating_ips_client.create_floating_ip()
|
||||
['floating_ip'])
|
||||
self.floatings[instance['id']] = floating_ip
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.compute_floating_ips_client.delete_floating_ip,
|
||||
floating_ip['id'])
|
||||
# Attach a floating IP
|
||||
self.compute_floating_ips_client.associate_floating_ip_to_server(
|
||||
floating_ip['ip'], instance['id'])
|
||||
# Check ssh
|
||||
ssh_client = self.get_remote_client(
|
||||
server_or_ip=floating_ip['ip'],
|
||||
username=self.ssh_user,
|
||||
private_key=self.keypair['private_key'])
|
||||
|
||||
# NOTE(u_glide): Workaround for bug #1465682
|
||||
ssh_client = ssh_client.ssh_client
|
||||
|
||||
self.share = self.shares_client.get_share(self.share['id'])
|
||||
if do_ping:
|
||||
server_ip = self.share['export_location'].split(":")[0]
|
||||
ssh_client.exec_command("ping -c 1 %s" % server_ip)
|
||||
return ssh_client
|
||||
|
||||
def mount_share(self, location, ssh_client, target_dir=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def umount_share(self, ssh_client, target_dir=None):
|
||||
target_dir = target_dir or "/mnt"
|
||||
ssh_client.exec_command("sudo umount %s" % target_dir)
|
||||
|
||||
def write_data(self, data, ssh_client):
|
||||
ssh_client.exec_command("echo \"%s\" | sudo tee /mnt/t1 && sudo sync" %
|
||||
data)
|
||||
|
||||
def read_data(self, ssh_client):
|
||||
data = ssh_client.exec_command("sudo cat /mnt/t1")
|
||||
return data.rstrip()
|
||||
|
||||
def migrate_share(self, share_id, dest_host, status, force_host_assisted):
|
||||
share = self._migrate_share(
|
||||
share_id, dest_host, status, force_host_assisted,
|
||||
self.shares_admin_v2_client)
|
||||
return share
|
||||
|
||||
def migration_complete(self, share_id, dest_host):
|
||||
return self._migration_complete(share_id, dest_host)
|
||||
|
||||
def create_share_network(self):
|
||||
self.net = self._create_network(namestart="manila-share")
|
||||
self.subnet = self._create_subnet(network=self.net,
|
||||
namestart="manila-share-sub")
|
||||
router = self._get_router()
|
||||
self._create_router_interface(subnet_id=self.subnet['id'],
|
||||
router_id=router['id'])
|
||||
self.share_net = self._create_share_network(
|
||||
neutron_net_id=self.net['id'],
|
||||
neutron_subnet_id=self.subnet['id'],
|
||||
name=data_utils.rand_name("sn-name"))
|
||||
|
||||
def _get_share_type(self):
|
||||
if CONF.share.default_share_type_name:
|
||||
return self.shares_client.get_share_type(
|
||||
CONF.share.default_share_type_name)['share_type']
|
||||
return self._create_share_type(
|
||||
data_utils.rand_name("share_type"),
|
||||
extra_specs={
|
||||
'snapshot_support': CONF.share.capability_snapshot_support,
|
||||
'driver_handles_share_servers': CONF.share.multitenancy_enabled
|
||||
},)['share_type']
|
||||
|
||||
def create_share(self, **kwargs):
|
||||
kwargs.update({
|
||||
'share_protocol': self.protocol,
|
||||
})
|
||||
if not ('share_type_id' in kwargs or 'snapshot_id' in kwargs):
|
||||
kwargs.update({'share_type_id': self._get_share_type()['id']})
|
||||
if CONF.share.multitenancy_enabled:
|
||||
kwargs.update({'share_network_id': self.share_net['id']})
|
||||
self.share = self._create_share(**kwargs)
|
||||
return self.share
|
||||
|
||||
def allow_access_ip(self, share_id, ip=None, instance=None, cleanup=True,
|
||||
snapshot=None):
|
||||
if instance and not ip:
|
||||
try:
|
||||
net_addresses = instance['addresses']
|
||||
first_address = net_addresses.values()[0][0]
|
||||
ip = first_address['addr']
|
||||
except Exception:
|
||||
LOG.debug("Instance: %s", instance)
|
||||
# In case on an error ip will be still none
|
||||
LOG.exception("Instance does not have a valid IP address."
|
||||
"Falling back to default")
|
||||
if not ip:
|
||||
ip = '0.0.0.0/0'
|
||||
|
||||
if snapshot:
|
||||
self._allow_access_snapshot(snapshot['id'], access_type='ip',
|
||||
access_to=ip, cleanup=cleanup)
|
||||
else:
|
||||
self._allow_access(share_id, access_type='ip', access_to=ip,
|
||||
cleanup=cleanup)
|
||||
|
||||
def provide_access_to_auxiliary_instance(self, instance, share=None,
|
||||
snapshot=None):
|
||||
share = share or self.share
|
||||
if self.protocol.lower() == 'cifs':
|
||||
self.allow_access_ip(
|
||||
share['id'], instance=instance, cleanup=False,
|
||||
snapshot=snapshot)
|
||||
elif not CONF.share.multitenancy_enabled:
|
||||
self.allow_access_ip(
|
||||
share['id'], ip=self.floatings[instance['id']]['ip'],
|
||||
instance=instance, cleanup=False, snapshot=snapshot)
|
||||
elif (CONF.share.multitenancy_enabled and
|
||||
self.protocol.lower() == 'nfs'):
|
||||
self.allow_access_ip(
|
||||
share['id'], instance=instance, cleanup=False,
|
||||
snapshot=snapshot)
|
||||
|
||||
def wait_for_active_instance(self, instance_id):
|
||||
waiters.wait_for_server_status(
|
||||
self.os_primary.servers_client, instance_id, "ACTIVE")
|
||||
return self.os_primary.servers_client.show_server(
|
||||
instance_id)["server"]
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_mount_share_one_vm(self):
|
||||
instance = self.boot_instance(wait_until="BUILD")
|
||||
self.create_share()
|
||||
instance = self.wait_for_active_instance(instance["id"])
|
||||
ssh_client = self.init_ssh(instance)
|
||||
|
||||
self.provide_access_to_auxiliary_instance(instance)
|
||||
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
locations = self.share['export_locations']
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
|
||||
for location in locations:
|
||||
self.mount_share(location, ssh_client)
|
||||
self.umount_share(ssh_client)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_read_write_two_vms(self):
|
||||
"""Boots two vms and writes/reads data on it."""
|
||||
test_data = "Some test data to write"
|
||||
|
||||
# Boot two VMs and create share
|
||||
instance1 = self.boot_instance(wait_until="BUILD")
|
||||
instance2 = self.boot_instance(wait_until="BUILD")
|
||||
self.create_share()
|
||||
instance1 = self.wait_for_active_instance(instance1["id"])
|
||||
instance2 = self.wait_for_active_instance(instance2["id"])
|
||||
|
||||
# Write data to first VM
|
||||
ssh_client_inst1 = self.init_ssh(instance1)
|
||||
self.provide_access_to_auxiliary_instance(instance1)
|
||||
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
locations = self.share['export_locations']
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
|
||||
self.mount_share(locations[0], ssh_client_inst1)
|
||||
self.addCleanup(self.umount_share,
|
||||
ssh_client_inst1)
|
||||
self.write_data(test_data, ssh_client_inst1)
|
||||
|
||||
# Read from second VM
|
||||
ssh_client_inst2 = self.init_ssh(instance2)
|
||||
self.provide_access_to_auxiliary_instance(instance2)
|
||||
self.mount_share(locations[0], ssh_client_inst2)
|
||||
self.addCleanup(self.umount_share,
|
||||
ssh_client_inst2)
|
||||
data = self.read_data(ssh_client_inst2)
|
||||
self.assertEqual(test_data, data)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.29")
|
||||
@testtools.skipUnless(CONF.share.run_host_assisted_migration_tests or
|
||||
CONF.share.run_driver_assisted_migration_tests,
|
||||
"Share migration tests are disabled.")
|
||||
@ddt.data(True, False)
|
||||
def test_migration_files(self, force_host_assisted):
|
||||
|
||||
if (force_host_assisted and
|
||||
not CONF.share.run_host_assisted_migration_tests):
|
||||
raise self.skipException("Host-assisted migration tests are "
|
||||
"disabled.")
|
||||
elif (not force_host_assisted and
|
||||
not CONF.share.run_driver_assisted_migration_tests):
|
||||
raise self.skipException("Driver-assisted migration tests are "
|
||||
"disabled.")
|
||||
|
||||
if self.protocol != "nfs":
|
||||
raise self.skipException("Only NFS protocol supported "
|
||||
"at this moment.")
|
||||
|
||||
pools = self.shares_admin_v2_client.list_pools(detail=True)['pools']
|
||||
|
||||
if len(pools) < 2:
|
||||
raise self.skipException("At least two different pool entries are "
|
||||
"needed to run share migration tests.")
|
||||
|
||||
instance = self.boot_instance(wait_until="BUILD")
|
||||
self.create_share()
|
||||
instance = self.wait_for_active_instance(instance["id"])
|
||||
self.share = self.shares_admin_v2_client.get_share(self.share['id'])
|
||||
|
||||
default_type = self.shares_v2_client.list_share_types(
|
||||
default=True)['share_type']
|
||||
|
||||
dest_pool = utils.choose_matching_backend(
|
||||
self.share, pools, default_type)
|
||||
|
||||
self.assertIsNotNone(dest_pool)
|
||||
self.assertIsNotNone(dest_pool.get('name'))
|
||||
|
||||
dest_pool = dest_pool['name']
|
||||
|
||||
ssh_client = self.init_ssh(instance)
|
||||
self.provide_access_to_auxiliary_instance(instance)
|
||||
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
self.assertNotEmpty(exports)
|
||||
exports = [x['path'] for x in exports]
|
||||
self.assertNotEmpty(exports)
|
||||
|
||||
self.mount_share(exports[0], ssh_client)
|
||||
|
||||
ssh_client.exec_command("sudo mkdir -p /mnt/f1")
|
||||
ssh_client.exec_command("sudo mkdir -p /mnt/f2")
|
||||
ssh_client.exec_command("sudo mkdir -p /mnt/f3")
|
||||
ssh_client.exec_command("sudo mkdir -p /mnt/f4")
|
||||
ssh_client.exec_command("sudo mkdir -p /mnt/f1/ff1")
|
||||
ssh_client.exec_command("sleep 1")
|
||||
ssh_client.exec_command(
|
||||
"sudo dd if=/dev/zero of=/mnt/f1/1m1.bin bs=1M count=1")
|
||||
ssh_client.exec_command(
|
||||
"sudo dd if=/dev/zero of=/mnt/f2/1m2.bin bs=1M count=1")
|
||||
ssh_client.exec_command(
|
||||
"sudo dd if=/dev/zero of=/mnt/f3/1m3.bin bs=1M count=1")
|
||||
ssh_client.exec_command(
|
||||
"sudo dd if=/dev/zero of=/mnt/f4/1m4.bin bs=1M count=1")
|
||||
ssh_client.exec_command(
|
||||
"sudo dd if=/dev/zero of=/mnt/f1/ff1/1m5.bin bs=1M count=1")
|
||||
ssh_client.exec_command("sudo chmod -R 555 /mnt/f3")
|
||||
ssh_client.exec_command("sudo chmod -R 777 /mnt/f4")
|
||||
|
||||
task_state = (constants.TASK_STATE_DATA_COPYING_COMPLETED
|
||||
if force_host_assisted
|
||||
else constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
|
||||
|
||||
self.share = self.migrate_share(
|
||||
self.share['id'], dest_pool, task_state, force_host_assisted)
|
||||
|
||||
if force_host_assisted:
|
||||
self.assertRaises(
|
||||
exceptions.SSHExecCommandFailed,
|
||||
ssh_client.exec_command,
|
||||
"dd if=/dev/zero of=/mnt/f1/1m6.bin bs=1M count=1")
|
||||
|
||||
self.umount_share(ssh_client)
|
||||
|
||||
self.share = self.migration_complete(self.share['id'], dest_pool)
|
||||
|
||||
new_exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
self.assertNotEmpty(new_exports)
|
||||
new_exports = [x['path'] for x in new_exports]
|
||||
self.assertNotEmpty(new_exports)
|
||||
|
||||
self.assertEqual(dest_pool, self.share['host'])
|
||||
self.assertEqual(constants.TASK_STATE_MIGRATION_SUCCESS,
|
||||
self.share['task_state'])
|
||||
|
||||
self.mount_share(new_exports[0], ssh_client)
|
||||
|
||||
output = ssh_client.exec_command("ls -lRA --ignore=lost+found /mnt")
|
||||
|
||||
self.umount_share(ssh_client)
|
||||
|
||||
self.assertIn('1m1.bin', output)
|
||||
self.assertIn('1m2.bin', output)
|
||||
self.assertIn('1m3.bin', output)
|
||||
self.assertIn('1m4.bin', output)
|
||||
self.assertIn('1m5.bin', output)
|
||||
|
||||
def _get_user_export_location(self, share=None, snapshot=None):
|
||||
user_export_location = None
|
||||
if share:
|
||||
if utils.is_microversion_lt(
|
||||
CONF.share.max_api_microversion, "2.9"):
|
||||
user_export_location = share['export_locations'][0]
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
user_export_location = locations[0]
|
||||
elif snapshot:
|
||||
exports = (self.shares_v2_client.
|
||||
list_snapshot_export_locations(snapshot['id']))
|
||||
locations = [x['path'] for x in exports]
|
||||
user_export_location = locations[0]
|
||||
self.assertIsNotNone(user_export_location)
|
||||
return user_export_location
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_snapshot_tests, "Snapshot tests are disabled.")
|
||||
def test_write_data_to_share_created_from_snapshot(self):
|
||||
if self.protocol.upper() == 'CIFS':
|
||||
msg = "Skipped for CIFS protocol because of bug/1649573"
|
||||
raise self.skipException(msg)
|
||||
|
||||
# 1 - Create UVM, ok, created
|
||||
instance = self.boot_instance(wait_until="BUILD")
|
||||
|
||||
# 2 - Create share S1, ok, created
|
||||
parent_share = self.create_share()
|
||||
instance = self.wait_for_active_instance(instance["id"])
|
||||
self.addCleanup(self.servers_client.delete_server, instance['id'])
|
||||
|
||||
# 3 - SSH to UVM, ok, connected
|
||||
ssh_client = self.init_ssh(instance)
|
||||
|
||||
# 4 - Provide RW access to S1, ok, provided
|
||||
self.provide_access_to_auxiliary_instance(instance, parent_share)
|
||||
|
||||
# 5 - Try mount S1 to UVM, ok, mounted
|
||||
user_export_location = self._get_user_export_location(parent_share)
|
||||
parent_share_dir = "/mnt/parent"
|
||||
ssh_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
|
||||
self.mount_share(user_export_location, ssh_client, parent_share_dir)
|
||||
self.addCleanup(self.umount_share, ssh_client, parent_share_dir)
|
||||
|
||||
# 6 - Create "file1", ok, created
|
||||
ssh_client.exec_command("sudo touch %s/file1" % parent_share_dir)
|
||||
|
||||
# 7 - Create snapshot SS1 from S1, ok, created
|
||||
snapshot = self._create_snapshot(parent_share['id'])
|
||||
|
||||
# 8 - Create "file2" in share S1 - ok, created. We expect that
|
||||
# snapshot will not contain any data created after snapshot creation.
|
||||
ssh_client.exec_command("sudo touch %s/file2" % parent_share_dir)
|
||||
|
||||
# 9 - Create share S2 from SS1, ok, created
|
||||
child_share = self.create_share(snapshot_id=snapshot["id"])
|
||||
|
||||
# 10 - Try mount S2 - fail, access denied. We test that child share
|
||||
# did not get access rules from parent share.
|
||||
user_export_location = self._get_user_export_location(child_share)
|
||||
child_share_dir = "/mnt/child"
|
||||
ssh_client.exec_command("sudo mkdir -p %s" % child_share_dir)
|
||||
self.assertRaises(
|
||||
exceptions.SSHExecCommandFailed,
|
||||
self.mount_share,
|
||||
user_export_location, ssh_client, child_share_dir,
|
||||
)
|
||||
|
||||
# 11 - Provide RW access to S2, ok, provided
|
||||
self.provide_access_to_auxiliary_instance(instance, child_share)
|
||||
|
||||
# 12 - Try mount S2, ok, mounted
|
||||
self.mount_share(user_export_location, ssh_client, child_share_dir)
|
||||
self.addCleanup(self.umount_share, ssh_client, child_share_dir)
|
||||
|
||||
# 13 - List files on S2, only "file1" exists
|
||||
output = ssh_client.exec_command("sudo ls -lRA %s" % child_share_dir)
|
||||
self.assertIn('file1', output)
|
||||
self.assertNotIn('file2', output)
|
||||
|
||||
# 14 - Create file3 on S2, ok, file created
|
||||
ssh_client.exec_command("sudo touch %s/file3" % child_share_dir)
|
||||
|
||||
# 15 - List files on S1, two files exist - "file1" and "file2"
|
||||
output = ssh_client.exec_command("sudo ls -lRA %s" % parent_share_dir)
|
||||
self.assertIn('file1', output)
|
||||
self.assertIn('file2', output)
|
||||
self.assertNotIn('file3', output)
|
||||
|
||||
# 16 - List files on S2, two files exist - "file1" and "file3"
|
||||
output = ssh_client.exec_command("sudo ls -lRA %s" % child_share_dir)
|
||||
self.assertIn('file1', output)
|
||||
self.assertNotIn('file2', output)
|
||||
self.assertIn('file3', output)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
@base.skip_if_microversion_lt("2.32")
|
||||
@testtools.skipUnless(CONF.share.run_mount_snapshot_tests,
|
||||
'Mountable snapshots tests are disabled.')
|
||||
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||
"Snapshot tests are disabled.")
|
||||
def test_read_mountable_snapshot(self):
|
||||
if self.protocol.upper() == 'CIFS':
|
||||
msg = "Skipped for CIFS protocol because of bug/1649573"
|
||||
raise self.skipException(msg)
|
||||
|
||||
# 1 - Create UVM, ok, created
|
||||
instance = self.boot_instance(wait_until="BUILD")
|
||||
|
||||
# 2 - Create share S1, ok, created
|
||||
parent_share = self.create_share()
|
||||
instance = self.wait_for_active_instance(instance["id"])
|
||||
self.addCleanup(self.servers_client.delete_server, instance['id'])
|
||||
|
||||
# 3 - SSH to UVM, ok, connected
|
||||
ssh_client = self.init_ssh(instance)
|
||||
|
||||
# 4 - Provide RW access to S1, ok, provided
|
||||
self.provide_access_to_auxiliary_instance(instance, parent_share)
|
||||
|
||||
# 5 - Try mount S1 to UVM, ok, mounted
|
||||
user_export_location = self._get_user_export_location(parent_share)
|
||||
parent_share_dir = "/mnt/parent"
|
||||
snapshot_dir = "/mnt/snapshot_dir"
|
||||
ssh_client.exec_command("sudo mkdir -p %s" % parent_share_dir)
|
||||
ssh_client.exec_command("sudo mkdir -p %s" % snapshot_dir)
|
||||
self.mount_share(user_export_location, ssh_client, parent_share_dir)
|
||||
self.addCleanup(self.umount_share, ssh_client, parent_share_dir)
|
||||
|
||||
# 6 - Create "file1", ok, created
|
||||
ssh_client.exec_command("sudo touch %s/file1" % parent_share_dir)
|
||||
|
||||
# 7 - Create snapshot SS1 from S1, ok, created
|
||||
snapshot = self._create_snapshot(parent_share['id'])
|
||||
|
||||
# 8 - Create "file2" in share S1 - ok, created. We expect that
|
||||
# snapshot will not contain any data created after snapshot creation.
|
||||
ssh_client.exec_command("sudo touch %s/file2" % parent_share_dir)
|
||||
|
||||
# 9 - Allow access to SS1
|
||||
self.provide_access_to_auxiliary_instance(instance, snapshot=snapshot)
|
||||
|
||||
# 10 - Mount SS1
|
||||
user_export_location = self._get_user_export_location(
|
||||
snapshot=snapshot)
|
||||
self.mount_share(user_export_location, ssh_client, snapshot_dir)
|
||||
self.addCleanup(self.umount_share, ssh_client, snapshot_dir)
|
||||
|
||||
# 11 - List files on SS1, only "file1" exists
|
||||
# NOTE(lseki): using ls without recursion to avoid permission denied
|
||||
# error while listing lost+found directory on LVM volumes
|
||||
output = ssh_client.exec_command("sudo ls -lA %s" % snapshot_dir)
|
||||
self.assertIn('file1', output)
|
||||
self.assertNotIn('file2', output)
|
||||
|
||||
# 12 - Try to create a file on SS1, should fail
|
||||
self.assertRaises(
|
||||
exceptions.SSHExecCommandFailed,
|
||||
ssh_client.exec_command,
|
||||
"sudo touch %s/file3" % snapshot_dir)
|
||||
|
||||
|
||||
class TestShareBasicOpsNFS(ShareBasicOpsBase):
|
||||
protocol = "nfs"
|
||||
|
||||
def mount_share(self, location, ssh_client, target_dir=None):
|
||||
target_dir = target_dir or "/mnt"
|
||||
ssh_client.exec_command(
|
||||
"sudo mount -vt nfs \"%s\" %s" % (location, target_dir))
|
||||
|
||||
|
||||
class TestShareBasicOpsCIFS(ShareBasicOpsBase):
|
||||
protocol = "cifs"
|
||||
|
||||
def mount_share(self, location, ssh_client, target_dir=None):
|
||||
location = location.replace("\\", "/")
|
||||
target_dir = target_dir or "/mnt"
|
||||
ssh_client.exec_command(
|
||||
"sudo mount.cifs \"%s\" %s -o guest" % (location, target_dir)
|
||||
)
|
||||
|
||||
|
||||
# NOTE(u_glide): this function is required to exclude ShareBasicOpsBase 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 type(test_case._tests[0]) is ShareBasicOpsBase:
|
||||
continue
|
||||
result.append(test_case)
|
||||
return loader.suiteClass(result)
|
@ -1,168 +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 netaddr import ip
|
||||
import random
|
||||
import re
|
||||
|
||||
import six
|
||||
from tempest import config
|
||||
import testtools
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
def get_microversion_as_tuple(microversion_str):
|
||||
"""Transforms string-like microversion to two-value tuple of integers.
|
||||
|
||||
Tuple of integers useful for microversion comparisons.
|
||||
"""
|
||||
regex = r"^([1-9]\d*)\.([1-9]\d*|0)$"
|
||||
match = re.match(regex, microversion_str)
|
||||
if not match:
|
||||
raise ValueError(
|
||||
"Microversion does not fit template 'x.y' - %s" % microversion_str)
|
||||
return int(match.group(1)), int(match.group(2))
|
||||
|
||||
|
||||
def is_microversion_gt(left, right):
|
||||
"""Is microversion for left is greater than the right one."""
|
||||
return get_microversion_as_tuple(left) > get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_ge(left, right):
|
||||
"""Is microversion for left is greater than or equal to the right one."""
|
||||
return get_microversion_as_tuple(left) >= get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_eq(left, right):
|
||||
"""Is microversion for left is equal to the right one."""
|
||||
return get_microversion_as_tuple(left) == get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_ne(left, right):
|
||||
"""Is microversion for left is not equal to the right one."""
|
||||
return get_microversion_as_tuple(left) != get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_le(left, right):
|
||||
"""Is microversion for left is less than or equal to the right one."""
|
||||
return get_microversion_as_tuple(left) <= get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_lt(left, right):
|
||||
"""Is microversion for left is less than the right one."""
|
||||
return get_microversion_as_tuple(left) < get_microversion_as_tuple(right)
|
||||
|
||||
|
||||
def is_microversion_supported(microversion):
|
||||
bottom = get_microversion_as_tuple(CONF.share.min_api_microversion)
|
||||
microversion = get_microversion_as_tuple(microversion)
|
||||
top = get_microversion_as_tuple(CONF.share.max_api_microversion)
|
||||
return bottom <= microversion <= top
|
||||
|
||||
|
||||
def skip_if_microversion_not_supported(microversion):
|
||||
"""Decorator for tests that are microversion-specific."""
|
||||
if not is_microversion_supported(microversion):
|
||||
reason = ("Skipped. Test requires microversion '%s'." % microversion)
|
||||
return testtools.skip(reason)
|
||||
return lambda f: f
|
||||
|
||||
|
||||
def skip_if_microversion_lt(microversion):
|
||||
"""Decorator for tests that are microversion-specific."""
|
||||
if is_microversion_lt(CONF.share.max_api_microversion, microversion):
|
||||
reason = ("Skipped. Test requires microversion greater than or "
|
||||
"equal to '%s'." % microversion)
|
||||
return testtools.skip(reason)
|
||||
return lambda f: f
|
||||
|
||||
|
||||
def rand_ip(network=False):
|
||||
"""This uses the TEST-NET-3 range of reserved IP addresses.
|
||||
|
||||
Using this range, which are reserved solely for use in
|
||||
documentation and example source code, should avoid any potential
|
||||
conflicts in real-world testing.
|
||||
"""
|
||||
test_net_3 = '203.0.113.'
|
||||
address = test_net_3 + six.text_type(random.randint(0, 255))
|
||||
if network:
|
||||
mask_length = six.text_type(random.randint(24, 32))
|
||||
address = '/'.join((address, mask_length))
|
||||
ip_network = ip.IPNetwork(address)
|
||||
return '/'.join((six.text_type(ip_network.network), mask_length))
|
||||
return address
|
||||
|
||||
|
||||
def rand_ipv6_ip(network=False):
|
||||
"""This uses the IPv6 documentation range of 2001:DB8::/32"""
|
||||
ran_add = ["%x" % random.randrange(0, 16**4) for i in range(6)]
|
||||
address = "2001:0DB8:" + ":".join(ran_add)
|
||||
if network:
|
||||
mask_length = six.text_type(random.randint(32, 128))
|
||||
address = '/'.join((address, mask_length))
|
||||
ip_network = ip.IPNetwork(address)
|
||||
return '/'.join((six.text_type(ip_network.network), mask_length))
|
||||
return address
|
||||
|
||||
|
||||
def choose_matching_backend(share, pools, share_type):
|
||||
extra_specs = {}
|
||||
# fix extra specs with string values instead of boolean
|
||||
for k, v in share_type['extra_specs'].items():
|
||||
extra_specs[k] = (True if six.text_type(v).lower() == 'true'
|
||||
else False if six.text_type(v).lower() == 'false'
|
||||
else v)
|
||||
selected_pool = next(
|
||||
(x for x in pools if (x['name'] != share['host'] and all(
|
||||
y in x['capabilities'].items() for y in extra_specs.items()))),
|
||||
None)
|
||||
|
||||
return selected_pool
|
||||
|
||||
|
||||
def get_configured_extra_specs(variation=None):
|
||||
"""Retrieve essential extra specs according to configuration in tempest.
|
||||
|
||||
:param variation: can assume possible values: None to be as configured in
|
||||
tempest; 'opposite_driver_modes' for as configured in tempest but
|
||||
inverse driver mode; 'invalid' for inverse as configured in tempest,
|
||||
ideal for negative tests.
|
||||
:return: dict containing essential extra specs.
|
||||
"""
|
||||
|
||||
extra_specs = {'storage_protocol': CONF.share.capability_storage_protocol}
|
||||
|
||||
if variation == 'invalid':
|
||||
extra_specs['driver_handles_share_servers'] = (
|
||||
not CONF.share.multitenancy_enabled)
|
||||
extra_specs['snapshot_support'] = (
|
||||
not CONF.share.capability_snapshot_support)
|
||||
|
||||
elif variation == 'opposite_driver_modes':
|
||||
extra_specs['driver_handles_share_servers'] = (
|
||||
not CONF.share.multitenancy_enabled)
|
||||
extra_specs['snapshot_support'] = (
|
||||
CONF.share.capability_snapshot_support)
|
||||
|
||||
else:
|
||||
extra_specs['driver_handles_share_servers'] = (
|
||||
CONF.share.multitenancy_enabled)
|
||||
extra_specs['snapshot_support'] = (
|
||||
CONF.share.capability_snapshot_support)
|
||||
|
||||
return extra_specs
|
@ -54,6 +54,7 @@
|
||||
|
||||
# Keep localrc to be able to set some vars in pre_test_hook
|
||||
export KEEP_LOCALRC=1
|
||||
export PROJECTS="openstack/manila-tempest-plugin $PROJECTS"
|
||||
|
||||
function pre_test_hook {
|
||||
# Build custom image if needed
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user