Merge "Remove the legacy "manila" CLI"

This commit is contained in:
Zuul
2026-02-09 19:46:43 +00:00
committed by Gerrit Code Review
37 changed files with 17 additions and 22299 deletions

View File

@@ -2,10 +2,14 @@
OpenStackClient Mapping Guide
=============================
.. note::
The legacy ``manila`` CLI has been removed. This guide is maintained for
historical reference to help users upgrading from older versions.
The following is a mapping between the legacy ``manila`` CLI client and
OpenStackClient. Command options are only shown when necessary.
.. only:: html
.. csv-table::

View File

@@ -2,26 +2,17 @@ Python bindings to the OpenStack Manila API
===========================================
This is a client for OpenStack Manila API. There's :doc:`a Python API
<user/api>` (the :mod:`manilaclient` module), and a :doc:`command-line script
<user/shell>` (installed as :program:`manila`). Each implements the entire
OpenStack Manila API. See :ref:`project-structure` for more information.
<user/api>` (the :mod:`manilaclient` module) for programmatic access, and
a command-line interface via the OpenStack CLI client. See
:ref:`project-structure` for more information.
You'll need credentials for an OpenStack cloud that implements the
Manila API in order to use the manila client.
Command-Line Reference
~~~~~~~~~~~~~~~~~~~~~~
There are two shell implementations in python-manilaclient.
.. important::
The legacy "manila" shell client is deprecated as of version ``5.0.0``.
A future version of python-manilaclient may not ship this legacy shell
client. If you rely on it, it is highly recommended that you begin using
the openstack CLI client right away. Refer to the `mapping guide
<cli/decoder.html>`_ to help with this transition.
The "openstack" CLI client intends to be fully compatible with the manila API:
Use the "openstack" CLI client to interact with the Manila API from the
command line:
.. toctree::
:maxdepth: 1
@@ -29,14 +20,6 @@ The "openstack" CLI client intends to be fully compatible with the manila API:
cli/osc_plugin_cli
cli/decoder
The legacy "manila" client is deprecated and may not support newer API
features:
.. toctree::
:maxdepth: 2
user/shell
Using the python module
~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -1,59 +0,0 @@
The :program:`manila` shell utility
=========================================
.. important::
This shell client is deprecated as of version ``5.0.0``. A future
version of python-manilaclient may not ship this legacy shell client. If
you rely on it, it is highly recommended that you begin using the
openstack CLI client right away. Refer to the `mapping guide
<../cli/decoder.html>`_ to help with this transition.
.. program:: manila
.. highlight:: bash
The :program:`manila` shell utility interacts with the OpenStack Manila API
from the command line. It supports the entirety of the OpenStack Manila API.
You'll need to provide :program:`manila` with your OpenStack username and API
key. You can do this with the `--os-username`, `--os-password` and
`--os-tenant-name` options, but it's easier to just set them as environment
variables by setting two environment variables:
.. envvar:: OS_USERNAME or MANILA_USERNAME
Your OpenStack Manila username.
.. envvar:: OS_PASSWORD or MANILA_PASSWORD
Your password.
.. envvar:: OS_TENANT_NAME or MANILA_PROJECT_ID
Project for work.
.. envvar:: OS_AUTH_URL or MANILA_URL
The OpenStack API server URL.
.. envvar:: OS_SHARE_API_VERSION
The OpenStack Shared Filesystems API version.
For example, in Bash you'd use::
export OS_USERNAME=foo
export OS_PASSWORD=bar
export OS_TENANT_NAME=foobarproject
export OS_AUTH_URL=http://...
export OS_SHARE_API_VERSION=2
From there, all shell commands take the form::
manila <command> [arguments...]
Run :program:`manila help` to get a full list of all possible commands,
and run :program:`manila help <command>` to get detailed help for that
command.
.. program-output:: manila --help

View File

@@ -1,3 +1,5 @@
# NOTE: The legacy "manila" CLI has been removed. This file is maintained
# for historical reference and migration purposes.
manila command,openstack command,command description
--version,module list,List the client software version
absolute-limits,share limits show --absolute,Print a list of absolute limits for a user
Can't render this file because it contains an unexpected character in line 1 and column 20.

View File

@@ -1,858 +0,0 @@
# Copyright 2011 OpenStack Foundation
# 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.
"""
Command-line interface to the OpenStack Manila API.
"""
import argparse
import csv
import glob
from importlib import util as importlib_util
import itertools
import logging
import os
import pkgutil
import sys
from oslo_utils import importutils
from manilaclient import api_versions
from manilaclient import client
from manilaclient.common import cliutils
from manilaclient.common import constants
from manilaclient import exceptions as exc
import manilaclient.extension
from manilaclient.v2 import shell as shell_v2
DEFAULT_OS_SHARE_API_VERSION = api_versions.MAX_VERSION
DEFAULT_MANILA_ENDPOINT_TYPE = 'publicURL'
DEFAULT_MAJOR_OS_SHARE_API_VERSION = "2"
V1_MAJOR_VERSION = '1'
V2_MAJOR_VERSION = '2'
try:
osprofiler_profiler = importutils.try_import("osprofiler.profiler")
except ImportError:
pass
logger = logging.getLogger(__name__)
class AllowOnlyOneAliasAtATimeAction(argparse.Action):
"""Allows only one alias of argument to be used at a time."""
def __call__(self, parser, namespace, values, option_string=None):
# NOTE(vponomaryov): this method is redefinition of
# argparse.Action.__call__ interface
if not hasattr(self, 'calls'):
self.calls = {}
if self.dest not in self.calls:
self.calls[self.dest] = set()
local_values = sorted(values) if isinstance(values, list) else values
self.calls[self.dest].add(str(local_values))
if len(self.calls[self.dest]) == 1:
setattr(namespace, self.dest, local_values)
else:
msg = "Only one alias is allowed at a time."
raise argparse.ArgumentError(self, msg)
class ManilaClientArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# NOTE(vponomaryov): Register additional action to be used by arguments
# with multiple aliases.
self.register('action', 'single_alias', AllowOnlyOneAliasAtATimeAction)
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
"""
self.print_usage(sys.stderr)
# FIXME(lzyeval): if changes occur in argparse.ArgParser._check_value
choose_from = ' (choose from'
progparts = self.prog.partition(' ')
self.exit(
2,
f"error: {message.split(choose_from)[0]}\n"
f"Try '{progparts[0]} help {progparts[2]}' "
f"for more information.\n",
)
def _get_option_tuples(self, option_string):
"""Avoid ambiguity in argument abbreviation.
Manilaclient uses aliases for command parameters and this method
is used for avoiding parameter ambiguity alert.
"""
option_tuples = super()._get_option_tuples(option_string)
if len(option_tuples) > 1:
opt_strings_list = []
opts = []
for opt in option_tuples:
if opt[0].option_strings not in opt_strings_list:
opt_strings_list.append(opt[0].option_strings)
opts.append(opt)
return opts
return option_tuples
class OpenStackManilaShell:
def get_base_parser(self):
parser = ManilaClientArgumentParser(
prog='manila',
description=__doc__.strip(),
epilog='See "manila help COMMAND" for help on a specific command.',
add_help=False,
formatter_class=OpenStackHelpFormatter,
)
# Global arguments
parser.add_argument(
'-h', '--help', action='store_true', help=argparse.SUPPRESS
)
parser.add_argument(
'--version', action='version', version=manilaclient.__version__
)
parser.add_argument(
'-d',
'--debug',
action='store_true',
default=cliutils.env(
'manilaclient_DEBUG', 'MANILACLIENT_DEBUG', default=False
),
help="Print debugging output.",
)
parser.add_argument(
'--os-cache',
default=cliutils.env('OS_CACHE', default=False),
action='store_true',
help='Use the auth token cache. Defaults to env[OS_CACHE].',
)
parser.add_argument(
'--os-reset-cache',
default=False,
action='store_true',
help='Delete cached password and auth token.',
)
parser.add_argument(
'--os-user-id',
metavar='<auth-user-id>',
default=cliutils.env('OS_USER_ID'),
help=('Defaults to env [OS_USER_ID].'),
)
parser.add_argument('--os_user_id', help=argparse.SUPPRESS)
parser.add_argument(
'--os-username',
metavar='<auth-user-name>',
default=cliutils.env('OS_USERNAME', 'MANILA_USERNAME'),
help='Defaults to env[OS_USERNAME].',
)
parser.add_argument('--os_username', help=argparse.SUPPRESS)
parser.add_argument(
'--os-password',
metavar='<auth-password>',
default=cliutils.env('OS_PASSWORD', 'MANILA_PASSWORD'),
help='Defaults to env[OS_PASSWORD].',
)
parser.add_argument('--os_password', help=argparse.SUPPRESS)
parser.add_argument(
'--os-tenant-name',
metavar='<auth-tenant-name>',
default=cliutils.env('OS_TENANT_NAME', 'MANILA_PROJECT_ID'),
help='Defaults to env[OS_TENANT_NAME].',
)
parser.add_argument('--os_tenant_name', help=argparse.SUPPRESS)
parser.add_argument(
'--os-project-name',
metavar='<auth-project-name>',
default=cliutils.env('OS_PROJECT_NAME'),
help=(
'Another way to specify tenant name. '
'This option is mutually exclusive with '
'--os-tenant-name. '
'Defaults to env[OS_PROJECT_NAME].'
),
)
parser.add_argument('--os_project_name', help=argparse.SUPPRESS)
parser.add_argument(
'--os-tenant-id',
metavar='<auth-tenant-id>',
default=cliutils.env('OS_TENANT_ID', 'MANILA_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].',
)
parser.add_argument('--os_tenant_id', help=argparse.SUPPRESS)
parser.add_argument(
'--os-project-id',
metavar='<auth-project-id>',
default=cliutils.env('OS_PROJECT_ID'),
help=(
'Another way to specify tenant ID. '
'This option is mutually exclusive with '
'--os-tenant-id. '
'Defaults to env[OS_PROJECT_ID].'
),
)
parser.add_argument('--os_project_id', help=argparse.SUPPRESS)
parser.add_argument(
'--os-user-domain-id',
metavar='<auth-user-domain-id>',
default=cliutils.env('OS_USER_DOMAIN_ID'),
help=(
'OpenStack user domain ID. Defaults to env[OS_USER_DOMAIN_ID].'
),
)
parser.add_argument('--os_user_domain_id', help=argparse.SUPPRESS)
parser.add_argument(
'--os-user-domain-name',
metavar='<auth-user-domain-name>',
default=cliutils.env('OS_USER_DOMAIN_NAME'),
help=(
'OpenStack user domain name. '
'Defaults to env[OS_USER_DOMAIN_NAME].'
),
)
parser.add_argument('--os_user_domain_name', help=argparse.SUPPRESS)
parser.add_argument(
'--os-project-domain-id',
metavar='<auth-project-domain-id>',
default=cliutils.env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].',
)
parser.add_argument('--os_project_domain_id', help=argparse.SUPPRESS)
parser.add_argument(
'--os-project-domain-name',
metavar='<auth-project-domain-name>',
default=cliutils.env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].',
)
parser.add_argument('--os_project_domain_name', help=argparse.SUPPRESS)
parser.add_argument(
'--os-auth-url',
metavar='<auth-url>',
default=cliutils.env('OS_AUTH_URL', 'MANILA_URL'),
help='Defaults to env[OS_AUTH_URL].',
)
parser.add_argument('--os_auth_url', help=argparse.SUPPRESS)
parser.add_argument(
'--os-region-name',
metavar='<region-name>',
default=cliutils.env('OS_REGION_NAME', 'MANILA_REGION_NAME'),
help='Defaults to env[OS_REGION_NAME].',
)
parser.add_argument('--os_region_name', help=argparse.SUPPRESS)
parser.add_argument(
'--os-token',
metavar='<token>',
default=cliutils.env('OS_TOKEN'),
help='Defaults to env[OS_TOKEN].',
)
parser.add_argument('--os_token', help=argparse.SUPPRESS)
parser.add_argument(
'--bypass-url',
metavar='<bypass-url>',
default=cliutils.env(
'OS_MANILA_BYPASS_URL', 'MANILACLIENT_BYPASS_URL'
),
help=(
"Use this API endpoint instead of the "
"Service Catalog. Defaults to "
"env[OS_MANILA_BYPASS_URL]."
),
)
parser.add_argument('--bypass_url', help=argparse.SUPPRESS)
parser.add_argument(
'--service-type',
metavar='<service-type>',
help='Defaults to compute for most actions.',
)
parser.add_argument('--service_type', help=argparse.SUPPRESS)
parser.add_argument(
'--service-name',
metavar='<service-name>',
default=cliutils.env(
'OS_MANILA_SERVICE_NAME', 'MANILA_SERVICE_NAME'
),
help='Defaults to env[OS_MANILA_SERVICE_NAME].',
)
parser.add_argument('--service_name', help=argparse.SUPPRESS)
parser.add_argument(
'--share-service-name',
metavar='<share-service-name>',
default=cliutils.env(
'OS_MANILA_SHARE_SERVICE_NAME', 'MANILA_share_service_name'
),
help='Defaults to env[OS_MANILA_SHARE_SERVICE_NAME].',
)
parser.add_argument('--share_service_name', help=argparse.SUPPRESS)
parser.add_argument(
'--endpoint-type',
metavar='<endpoint-type>',
default=cliutils.env(
'OS_MANILA_ENDPOINT_TYPE',
'MANILA_ENDPOINT_TYPE',
default=DEFAULT_MANILA_ENDPOINT_TYPE,
),
help='Defaults to env[OS_MANILA_ENDPOINT_TYPE] or '
+ DEFAULT_MANILA_ENDPOINT_TYPE
+ '.',
)
parser.add_argument('--endpoint_type', help=argparse.SUPPRESS)
parser.add_argument(
'--os-share-api-version',
metavar='<share-api-ver>',
default=cliutils.env(
'OS_SHARE_API_VERSION', default=DEFAULT_OS_SHARE_API_VERSION
),
help='Accepts 1.x to override default '
'to env[OS_SHARE_API_VERSION].',
)
parser.add_argument('--os_share_api_version', help=argparse.SUPPRESS)
parser.add_argument(
'--os-cacert',
metavar='<ca-certificate>',
default=cliutils.env('OS_CACERT', default=None),
help='Specify a CA bundle file to use in '
'verifying a TLS (https) server certificate. '
'Defaults to env[OS_CACERT].',
)
parser.add_argument(
'--insecure',
default=cliutils.env(
'manilaclient_INSECURE', 'MANILACLIENT_INSECURE', default=False
),
action='store_true',
help=argparse.SUPPRESS,
)
parser.add_argument(
'--retries',
metavar='<retries>',
type=int,
default=0,
help='Number of retries.',
)
parser.add_argument(
'--os-cert',
metavar='<certificate>',
default=cliutils.env('OS_CERT'),
help='Defaults to env[OS_CERT].',
)
parser.add_argument('--os_cert', help=argparse.SUPPRESS)
parser.add_argument(
'--os-key',
metavar='<key>',
default=cliutils.env('OS_KEY'),
help='Defaults to env[OS_KEY].',
)
parser.add_argument('--os_key', help=argparse.SUPPRESS)
if osprofiler_profiler:
parser.add_argument(
'--profile',
metavar='HMAC_KEY',
default=cliutils.env('OS_PROFILE'),
help='HMAC key to use for encrypting '
'context data for performance profiling '
'of operation. This key needs to match the '
'one configured on the manila api server. '
'Without key the profiling will not be '
'triggered even if osprofiler is enabled '
'on server side. Defaults to '
'env[OS_PROFILE].',
)
parser.set_defaults(func=self.do_help)
parser.set_defaults(command='')
return parser
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
try:
actions_module = {
V2_MAJOR_VERSION: shell_v2,
}[version]
except KeyError:
actions_module = shell_v2
self._find_actions(subparsers, actions_module)
self._find_actions(subparsers, self)
for extension in self.extensions:
self._find_actions(subparsers, extension.module)
self._add_bash_completion_subparser(subparsers)
return parser
def _discover_extensions(self, api_version):
extensions = []
for name, module in itertools.chain(
self._discover_via_python_path(),
self._discover_via_contrib_path(api_version),
):
extension = manilaclient.extension.Extension(name, module)
extensions.append(extension)
return extensions
def _discover_via_python_path(self):
for module_loader, name, ispkg in pkgutil.iter_modules():
if name.endswith('python_manilaclient_ext'):
if not hasattr(module_loader, 'load_module'):
# Python 2.6 compat: actually get an ImpImporter obj
module_loader = module_loader.find_module(name)
module = module_loader.load_module(name)
yield name, module
def _load_module(self, name, path):
module_spec = importlib_util.spec_from_file_location(name, path)
module = importlib_util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module
def _discover_via_contrib_path(self, api_version):
module_path = os.path.dirname(os.path.abspath(__file__))
version_str = 'v' + api_version.get_major_version()
ext_path = os.path.join(module_path, version_str, 'contrib')
ext_glob = os.path.join(ext_path, "*.py")
for ext_path in glob.iglob(ext_glob):
name = os.path.basename(ext_path)[:-3]
if name == "__init__":
continue
module = self._load_module(name, ext_path)
yield name, module
def _add_bash_completion_subparser(self, subparsers):
subparser = subparsers.add_parser(
'bash_completion',
add_help=False,
formatter_class=OpenStackHelpFormatter,
)
self.subcommands['bash_completion'] = subparser
subparser.set_defaults(func=self.do_bash_completion)
def _find_actions(self, subparsers, actions_module):
for attr in (a for a in dir(actions_module) if a.startswith('do_')):
# I prefer to be hypen-separated instead of underscores.
command = attr[3:].replace('_', '-')
callback = getattr(actions_module, attr)
desc = callback.__doc__ or ''
help = desc.strip()
arguments = getattr(callback, 'arguments', [])
subparser = subparsers.add_parser(
command,
help=help,
description=desc,
add_help=False,
formatter_class=OpenStackHelpFormatter,
)
subparser.add_argument(
'-h',
'--help',
action='help',
help=argparse.SUPPRESS,
)
self.subcommands[command] = subparser
for args, kwargs in arguments:
subparser.add_argument(*args, **kwargs)
subparser.set_defaults(func=callback)
def setup_debugging(self, debug):
if not debug:
return
streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
logging.basicConfig(level=logging.DEBUG, format=streamformat)
logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(
logging.WARNING
)
logging.getLogger('keystoneauth1.session').setLevel(logging.WARNING)
def _build_subcommands_and_extensions(self, os_api_version, argv, options):
self.extensions = self._discover_extensions(os_api_version)
self._run_extension_hooks('__pre_parse_args__')
self.parser = self.get_subcommand_parser(
os_api_version.get_major_version()
)
if argv and len(argv) > 1 and '--help' in argv:
argv = [x for x in argv if x != '--help']
if argv[0] in self.subcommands:
self.subcommands[argv[0]].print_help()
return False
if options.help or not argv:
self.parser.print_help()
return False
args = self.parser.parse_args(argv)
self._run_extension_hooks('__post_parse_args__', args)
return args
def main(self, argv):
# Parse args once to find version and debug settings
parser = self.get_base_parser()
(options, args) = parser.parse_known_args(argv)
self.setup_debugging(options.debug)
os_api_version = self._validate_input_api_version(options)
# build available subcommands based on version
args = self._build_subcommands_and_extensions(
os_api_version, argv, options
)
if not args:
return 0
# Short-circuit and deal with help right away.
if args.func == self.do_help:
self.do_help(args)
return 0
elif args.func == self.do_bash_completion:
self.do_bash_completion(args)
return 0
if not options.os_share_api_version:
api_version = api_versions.get_api_version(
DEFAULT_MAJOR_OS_SHARE_API_VERSION
)
else:
api_version = api_versions.get_api_version(
options.os_share_api_version
)
major_version_string = str(api_version.ver_major)
os_service_type = args.service_type
if not os_service_type:
os_service_type = constants.SERVICE_TYPES[major_version_string]
os_endpoint_type = args.endpoint_type or DEFAULT_MANILA_ENDPOINT_TYPE
cert = args.os_cert or None
if cert and args.os_key:
cert = cert, args.os_key
client_args = dict(
username=args.os_username,
password=args.os_password,
project_name=args.os_project_name or args.os_tenant_name,
auth_url=args.os_auth_url,
insecure=args.insecure,
region_name=args.os_region_name,
tenant_id=args.os_project_id or args.os_tenant_id,
endpoint_type=os_endpoint_type,
extensions=self.extensions,
service_type=os_service_type,
service_name=args.service_name,
retries=options.retries,
http_log_debug=args.debug,
cacert=args.os_cacert,
use_keyring=args.os_cache,
force_new_token=args.os_reset_cache,
user_id=args.os_user_id,
user_domain_id=args.os_user_domain_id,
user_domain_name=args.os_user_domain_name,
project_domain_id=args.os_project_domain_id,
project_domain_name=args.os_project_domain_name,
cert=cert,
input_auth_token=args.os_token,
service_catalog_url=args.bypass_url,
)
# Handle deprecated parameters
if args.share_service_name:
client_args['share_service_name'] = args.share_service_name
self._validate_required_options(
args.os_tenant_name,
args.os_tenant_id,
args.os_project_name,
args.os_project_id,
args.os_token,
args.bypass_url,
client_args['auth_url'],
)
# This client is needed to discover the server api version.
temp_client = client.Client(
manilaclient.API_MAX_VERSION, **client_args
)
self.cs, discovered_version = self._discover_client(
temp_client,
os_api_version,
os_endpoint_type,
os_service_type,
client_args,
)
args = self._build_subcommands_and_extensions(
discovered_version, argv, options
)
profile = osprofiler_profiler and options.profile
if profile:
osprofiler_profiler.init(options.profile)
try:
decoder_path = '{}/{}'.format(
os.path.dirname(os.path.abspath(__file__)),
'osc/v2/data/manila.csv',
)
with open(decoder_path) as f:
decoder_data = {
r['manila command']: r['openstack command']
for r in csv.DictReader(f, skipinitialspace=True)
}
except Exception:
# this is fine
decoder_data = {}
deprecation_message = (
"manila CLI is deprecated and will be removed "
"in the future. Use openstack CLI instead."
)
cmd = args.func.__name__.lstrip('do_').replace("_", "-")
if decoder_data and cmd in decoder_data:
deprecation_message = " ".join(
[
deprecation_message,
"The equivalent command is \" openstack",
f"{decoder_data[cmd]}",
"\"",
]
)
print(deprecation_message, file=sys.stderr)
args.func(self.cs, args)
if profile:
trace_id = osprofiler_profiler.get().get_base_id()
print(f"Profiling trace ID: {trace_id}")
print(
"To display trace use next command:\n"
f"osprofiler trace show --html {trace_id} "
)
def _discover_client(
self,
current_client,
os_api_version,
os_endpoint_type,
os_service_type,
client_args,
):
if os_api_version == manilaclient.API_DEPRECATED_VERSION:
discovered_version = manilaclient.API_DEPRECATED_VERSION
os_service_type = constants.V1_SERVICE_TYPE
else:
discovered_version = api_versions.discover_version(
current_client, os_api_version
)
if not os_endpoint_type:
os_endpoint_type = DEFAULT_MANILA_ENDPOINT_TYPE
if not os_service_type:
os_service_type = self._discover_service_type(discovered_version)
if (
discovered_version != manilaclient.API_MAX_VERSION
or os_service_type != constants.V1_SERVICE_TYPE
or os_endpoint_type != DEFAULT_MANILA_ENDPOINT_TYPE
):
client_args['version'] = discovered_version
client_args['service_type'] = os_service_type
client_args['endpoint_type'] = os_endpoint_type
return (
client.Client(discovered_version, **client_args),
discovered_version,
)
else:
return current_client, discovered_version
def _discover_service_type(self, discovered_version):
major_version = discovered_version.get_major_version()
service_type = constants.SERVICE_TYPES[major_version]
return service_type
def _validate_input_api_version(self, options):
if not options.os_share_api_version:
api_version = manilaclient.API_MAX_VERSION
else:
api_version = api_versions.get_api_version(
options.os_share_api_version
)
return api_version
def _validate_required_options(
self,
tenant_name,
tenant_id,
project_name,
project_id,
token,
service_catalog_url,
auth_url,
):
if token and not service_catalog_url:
raise exc.CommandError(
"bypass_url missing: When specifying a token the bypass_url "
"must be set via --bypass-url or env[OS_MANILA_BYPASS_URL]"
)
if service_catalog_url and not token:
raise exc.CommandError(
"Token missing: When specifying a bypass_url a token must be "
"set via --os-token or env[OS_TOKEN]"
)
if token and service_catalog_url:
return
if not (tenant_name or tenant_id or project_name or project_id):
raise exc.CommandError(
"You must provide a tenant_name, tenant_id, "
"project_id or project_name (with "
"project_domain_name or project_domain_id) via "
"--os-tenant-name or env[OS_TENANT_NAME], "
"--os-tenant-id or env[OS_TENANT_ID], "
"--os-project-id or env[OS_PROJECT_ID], "
"--os-project-name or env[OS_PROJECT_NAME], "
"--os-project-domain-id or env[OS_PROJECT_DOMAIN_ID] and "
"--os-project-domain-name or env[OS_PROJECT_DOMAIN_NAME]."
)
if not auth_url:
raise exc.CommandError(
"You must provide an auth url "
"via either --os-auth-url or env[OS_AUTH_URL]"
)
def _run_extension_hooks(self, hook_type, *args, **kwargs):
"""Run hooks for all registered extensions."""
for extension in self.extensions:
extension.run_hooks(hook_type, *args, **kwargs)
def do_bash_completion(self, args):
"""Print arguments for bash_completion.
Prints all of the commands and options to stdout so that the
manila.bash_completion script doesn't have to hard code them.
"""
commands = set()
options = set()
for sc_str, sc in list(self.subcommands.items()):
commands.add(sc_str)
for option in sc._optionals._option_string_actions:
options.add(option)
commands.remove('bash-completion')
commands.remove('bash_completion')
print(' '.join(commands | options))
@cliutils.arg(
'command',
metavar='<subcommand>',
nargs='?',
help='Display help for <subcommand>',
)
def do_help(self, args):
"""Display help about this program or one of its subcommands."""
if args.command:
if args.command in self.subcommands:
self.subcommands[args.command].print_help()
else:
raise exc.CommandError(
f"'{args.command}' is not a valid subcommand"
)
else:
self.parser.print_help()
# I'm picky about my shell help.
class OpenStackHelpFormatter(argparse.HelpFormatter):
def start_section(self, heading):
# Title-case the headings
heading = f'{heading[0].upper()}{heading[1:]}'
super().start_section(heading)
def main():
try:
OpenStackManilaShell().main(sys.argv[1:])
except KeyboardInterrupt:
print("... terminating manila client", file=sys.stderr)
sys.exit(130)
except Exception as e:
logger.debug(e, exc_info=1)
print(f"ERROR: {str(e)}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -1,649 +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 re
import traceback
from oslo_log import log
from tempest.lib.cli import base
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from manilaclient.common import constants
from manilaclient import config
from manilaclient.tests.functional import client
from manilaclient.tests.functional import utils
CONF = config.CONF
LOG = log.getLogger(__name__)
class handle_cleanup_exceptions:
"""Handle exceptions raised with cleanup operations.
Always suppress errors when lib_exc.NotFound or lib_exc.Forbidden
are raised.
Suppress all other exceptions only in case config opt
'suppress_errors_in_cleanup' is True.
"""
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
if isinstance(exc_value, (lib_exc.NotFound, lib_exc.Forbidden)):
return True
elif CONF.suppress_errors_in_cleanup:
LOG.error("Suppressed cleanup error: \n%s", traceback.format_exc())
return True
return False # Don't suppress cleanup errors
class BaseTestCase(base.ClientTestBase):
# Will be cleaned up after test suite run
class_resources = []
# Will be cleaned up after single test run
method_resources = []
def setUp(self):
super().setUp()
self.addCleanup(self.clear_resources)
@classmethod
def tearDownClass(cls):
super().tearDownClass()
cls.clear_resources(cls.class_resources)
@classmethod
def clear_resources(cls, resources=None):
"""Deletes resources, that were created in test suites.
This method tries to remove resources from resource list,
if it is not found, assume it was deleted in test itself.
It is expected, that all resources were added as LIFO
due to restriction of deletion resources, that are in the chain.
:param resources: dict with keys 'type','id','client',
'deletion_params' and 'deleted'. Optional 'deletion_params'
contains additional data needed to delete some type of resources.
Ex:
params = {
'type': 'share_network_subnet',
'id': 'share-network-subnet-id',
'client': None,
'deletion_params': {
'share_network': 'share-network-id',
},
'deleted': False,
}
"""
if resources is None:
resources = cls.method_resources
for res in resources:
if "deleted" not in res:
res["deleted"] = False
if "client" not in res:
res["client"] = cls.get_cleanup_client()
if not res["deleted"]:
res_id = res["id"]
client = res["client"]
deletion_params = res.get("deletion_params")
with handle_cleanup_exceptions():
# TODO(vponomaryov): add support for other resources
if res["type"] == "share_type":
client.delete_share_type(
res_id, microversion=res["microversion"]
)
client.wait_for_share_type_deletion(
res_id, microversion=res["microversion"]
)
elif res["type"] == "share_network":
client.delete_share_network(
res_id, microversion=res["microversion"]
)
client.wait_for_share_network_deletion(
res_id, microversion=res["microversion"]
)
elif res["type"] == "share_network_subnet":
client.delete_share_network_subnet(
share_network_subnet=res_id,
share_network=deletion_params["share_network"],
microversion=res["microversion"],
)
client.wait_for_share_network_subnet_deletion(
share_network_subnet=res_id,
share_network=deletion_params["share_network"],
microversion=res["microversion"],
)
elif res["type"] == "share":
client.delete_share(
res_id, microversion=res["microversion"]
)
client.wait_for_share_deletion(
res_id, microversion=res["microversion"]
)
elif res["type"] == "snapshot":
client.delete_snapshot(
res_id, microversion=res["microversion"]
)
client.wait_for_snapshot_deletion(
res_id, microversion=res["microversion"]
)
elif res["type"] == "share_replica":
client.delete_share_replica(
res_id, microversion=res["microversion"]
)
client.wait_for_share_replica_deletion(
res_id, microversion=res["microversion"]
)
else:
LOG.warning(
"Provided unsupported resource type for "
"cleanup '%s'. Skipping.",
res["type"],
)
res["deleted"] = True
@classmethod
def get_admin_client(cls):
manilaclient = client.ManilaCLIClient(
username=CONF.admin_username,
password=CONF.admin_password,
tenant_name=CONF.admin_tenant_name,
project_domain_name=CONF.admin_project_domain_name or None,
project_domain_id=CONF.admin_project_domain_id or None,
user_domain_name=CONF.admin_user_domain_name or None,
user_domain_id=CONF.admin_user_domain_id or None,
uri=CONF.admin_auth_url or CONF.auth_url,
insecure=CONF.insecure,
cli_dir=CONF.manila_exec_dir,
)
# Set specific for admin project share network
manilaclient.share_network = CONF.admin_share_network
return manilaclient
@classmethod
def get_user_client(cls):
manilaclient = client.ManilaCLIClient(
username=CONF.username,
password=CONF.password,
tenant_name=CONF.tenant_name,
project_domain_name=CONF.project_domain_name or None,
project_domain_id=CONF.project_domain_id or None,
user_domain_name=CONF.user_domain_name or None,
user_domain_id=CONF.user_domain_id or None,
uri=CONF.auth_url,
insecure=CONF.insecure,
cli_dir=CONF.manila_exec_dir,
)
# Set specific for user project share network
manilaclient.share_network = CONF.share_network
return manilaclient
@property
def admin_client(self):
if not hasattr(self, '_admin_client'):
self._admin_client = self.get_admin_client()
return self._admin_client
@property
def user_client(self):
if not hasattr(self, '_user_client'):
self._user_client = self.get_user_client()
return self._user_client
def _get_clients(self):
return {'admin': self.admin_client, 'user': self.user_client}
def skip_if_microversion_not_supported(self, microversion):
if not utils.is_microversion_supported(microversion):
raise self.skipException(
f"Microversion '{microversion}' is not supported."
)
@classmethod
def create_share_type(
cls,
name=None,
driver_handles_share_servers=True,
snapshot_support=None,
create_share_from_snapshot=None,
revert_to_snapshot=None,
mount_snapshot=None,
is_public=True,
client=None,
cleanup_in_class=False,
microversion=None,
extra_specs=None,
description=None,
):
if client is None:
client = cls.get_admin_client()
data = {
"name": name,
"driver_handles_share_servers": driver_handles_share_servers,
"snapshot_support": snapshot_support,
"is_public": is_public,
"microversion": microversion,
"extra_specs": extra_specs,
"create_share_from_snapshot": create_share_from_snapshot,
"revert_to_snapshot": revert_to_snapshot,
"mount_snapshot": mount_snapshot,
}
if description:
data["description"] = description
share_type = client.create_share_type(**data)
resource = {
"type": "share_type",
"id": share_type["ID"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_type
@classmethod
def update_share_type(
cls,
share_type_id,
name=None,
is_public=None,
client=None,
microversion=None,
description=None,
):
if client is None:
client = cls.get_admin_client()
data = {
"share_type_id": share_type_id,
"microversion": microversion,
}
if name is not None:
data["name"] = name
if description is not None:
data["description"] = description
if is_public is not None:
data["is_public"] = is_public
share_type = client.update_share_type(**data)
return share_type
@classmethod
def create_share_network(
cls,
name=None,
description=None,
neutron_net_id=None,
neutron_subnet_id=None,
availability_zone=None,
client=None,
cleanup_in_class=False,
microversion=None,
):
if client is None:
client = cls.get_admin_client()
share_network = client.create_share_network(
name=name,
description=description,
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
availability_zone=availability_zone,
microversion=microversion,
)
resource = {
"type": "share_network",
"id": share_network["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_network
@classmethod
def add_share_network_subnet(
cls,
share_network,
neutron_net_id=None,
neutron_subnet_id=None,
availability_zone=None,
client=None,
cleanup_in_class=False,
microversion=None,
):
if client is None:
client = cls.get_admin_client()
share_network_subnet = client.add_share_network_subnet(
share_network, neutron_net_id, neutron_subnet_id, availability_zone
)
resource = {
"type": "share_network_subnet",
"id": share_network_subnet["id"],
"client": client,
"deletion_params": {
"share_network": share_network,
},
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_network_subnet
@classmethod
def create_share(
cls,
share_protocol=None,
size=None,
share_network=None,
share_type=None,
name=None,
description=None,
public=False,
snapshot=None,
metadata=None,
client=None,
use_wait_option=False,
cleanup_in_class=False,
wait_for_creation=True,
microversion=None,
):
client = client or cls.get_admin_client()
data = {
'share_protocol': share_protocol or client.share_protocol,
'size': size or 1,
'name': name,
'description': description,
'public': public,
'snapshot': snapshot,
'metadata': metadata or {},
'microversion': microversion,
'wait': use_wait_option,
}
share_type = share_type or CONF.share_type
share_network = share_network or cls._determine_share_network_to_use(
client, share_type, microversion=microversion
)
data['share_type'] = share_type
data['share_network'] = share_network
share = client.create_share(**data)
resource = {
"type": "share",
"id": share["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
if wait_for_creation and not use_wait_option:
client.wait_for_resource_status(
share['id'], constants.STATUS_AVAILABLE
)
return share
@classmethod
def delete_share(
cls,
shares_to_delete,
share_group_id=None,
wait=False,
client=None,
microversion=None,
):
client = client or cls.get_admin_client()
client.delete_share(
shares_to_delete,
share_group_id=share_group_id,
wait=wait,
microversion=microversion,
)
@classmethod
def soft_delete_share(
cls, shares_to_soft_delete, client=None, microversion=None
):
client = client or cls.get_admin_client()
client.soft_delete_share(
shares_to_soft_delete, microversion=microversion
)
@classmethod
def restore_share(cls, shares_to_restore, client=None, microversion=None):
client = client or cls.get_admin_client()
client.restore_share(shares_to_restore, microversion=microversion)
@classmethod
def create_share_transfer(
cls, share_id, name=None, client=None, microversion=None
):
client = client or cls.get_admin_client()
return client.create_share_transfer(
share_id, name=name, microversion=microversion
)
@classmethod
def delete_share_transfer(cls, transfer, client=None, microversion=None):
client = client or cls.get_admin_client()
client.delete_share_transfer(transfer, microversion=microversion)
@classmethod
def get_share_transfer(cls, transfer, client=None, microversion=None):
client = client or cls.get_admin_client()
return client.get_share_transfer(transfer, microversion=microversion)
@classmethod
def list_share_transfer(cls, client=None, microversion=None):
client = client or cls.get_admin_client()
return client.list_share_transfer(microversion=microversion)
@classmethod
def accept_share_transfer(
cls, transfer, auth_key, client=None, microversion=None
):
client = client or cls.get_admin_client()
client.accept_share_transfer(
transfer, auth_key, microversion=microversion
)
@classmethod
def _determine_share_network_to_use(
cls, client, share_type, microversion=None
):
"""Determine what share network we need from the share type."""
# Get share type, determine if we need the share network
share_type = client.get_share_type(
share_type, microversion=microversion
)
dhss_pattern = re.compile('driver_handles_share_servers : ([a-zA-Z]+)')
dhss = dhss_pattern.search(share_type['required_extra_specs']).group(1)
return client.share_network if dhss.lower() == 'true' else None
@classmethod
def create_security_service(
cls,
type='ldap',
name=None,
description=None,
dns_ip=None,
ou=None,
server=None,
domain=None,
user=None,
password=None,
default_ad_site=None,
client=None,
cleanup_in_class=False,
microversion=None,
):
if client is None:
client = cls.get_admin_client()
data = {
'type': type,
'name': name,
'description': description,
'user': user,
'password': password,
'server': server,
'domain': domain,
'dns_ip': dns_ip,
'ou': ou,
'microversion': microversion,
'default_ad_site': default_ad_site,
}
ss = client.create_security_service(**data)
resource = {
"type": "share",
"id": ss["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return ss
@classmethod
def create_snapshot(
cls,
share,
name=None,
description=None,
force=False,
client=None,
wait_for_creation=True,
cleanup_in_class=False,
microversion=None,
):
if client is None:
client = cls.get_admin_client()
data = {
'share': share,
'name': name,
'description': description,
'force': force,
'microversion': microversion,
}
snapshot = client.create_snapshot(**data)
resource = {
"type": "snapshot",
"id": snapshot["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
if wait_for_creation:
client.wait_for_snapshot_status(snapshot['id'], 'available')
return snapshot
@classmethod
def create_message(
cls,
client=None,
wait_for_creation=True,
cleanup_in_class=False,
microversion=None,
):
"""Trigger a 'no valid host' situation to generate a message."""
if client is None:
client = cls.get_admin_client()
extra_specs = {
'vendor_name': 'foobar',
}
share_type_name = data_utils.rand_name("share-type")
cls.create_share_type(
name=share_type_name,
extra_specs=extra_specs,
driver_handles_share_servers=False,
client=client,
cleanup_in_class=cleanup_in_class,
microversion=microversion,
)
share_name = data_utils.rand_name("share")
share = cls.create_share(
name=share_name,
share_type=share_type_name,
cleanup_in_class=cleanup_in_class,
microversion=microversion,
wait_for_creation=False,
client=client,
)
client.wait_for_resource_status(share['id'], constants.STATUS_ERROR)
message = client.wait_for_message(share['id'])
resource = {
"type": "message",
"id": message["ID"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return message
@classmethod
def create_share_replica(
cls,
share_id,
client=None,
wait_for_creation=True,
cleanup_in_class=False,
availability_zone=None,
share_network=None,
microversion=None,
):
client = client or cls.get_user_client()
share_replica = client.create_share_replica(
share_id,
availability_zone=availability_zone,
share_network=share_network,
microversion=microversion,
)
if wait_for_creation:
share_replica = client.wait_for_share_replica_status(
share_replica['id']
)
resource = {
"type": "share_replica",
"id": share_replica["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_replica

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +0,0 @@
# Copyright 2016 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from oslo_utils import uuidutils
from manilaclient.tests.functional import base
@ddt.ddt
class ManilaClientTestAvailabilityZonesReadOnly(base.BaseTestCase):
@ddt.data("2.6", "2.7", "2.22")
def test_availability_zone_list(self, microversion):
self.skip_if_microversion_not_supported(microversion)
azs = self.user_client.list_availability_zones(
microversion=microversion
)
for az in azs:
self.assertEqual(4, len(az))
for key in ('Id', 'Name', 'Created_At', 'Updated_At'):
self.assertIn(key, az)
self.assertTrue(uuidutils.is_uuid_like(az['Id']))
self.assertIsNotNone(az['Name'])
self.assertIsNotNone(az['Created_At'])
@ddt.data(
('name', ['Name']),
('name,id', ['Name', 'Id']),
('name,created_at', ['Name', 'Created_At']),
('name,id,created_at', ['Name', 'Id', 'Created_At']),
)
@ddt.unpack
def test_availability_zone_list_with_columns(self, columns_arg, expected):
azs = self.user_client.list_availability_zones(columns=columns_arg)
for az in azs:
self.assertEqual(len(expected), len(az))
for key in expected:
self.assertIn(key, az)
if 'Id' in expected:
self.assertTrue(uuidutils.is_uuid_like(az['Id']))
if 'Name' in expected:
self.assertIsNotNone(az['Name'])
if 'Created_At' in expected:
self.assertIsNotNone(az['Created_At'])

View File

@@ -1,73 +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 re
import ddt
from manilaclient.tests.functional import base
@ddt.ddt
class ManilaClientTestCommonReadOnly(base.BaseTestCase):
@ddt.data('admin', 'user')
def test_manila_version(self, role):
self.clients[role].manila('', flags='--version')
@ddt.data('admin', 'user')
def test_help(self, role):
help_text = self.clients[role].manila('help')
lines = help_text.split('\n')
self.assertFirstLineStartsWith(lines, 'usage: manila')
commands = []
cmds_start = lines.index('Positional arguments:')
cmds_end = lines.index('Options:')
command_pattern = re.compile(r'^ {4}([a-z0-9\-\_]+)')
for line in lines[cmds_start:cmds_end]:
match = command_pattern.match(line)
if match:
commands.append(match.group(1))
commands = set(commands)
wanted_commands = set(
(
'absolute-limits',
'list',
'help',
'quota-show',
'access-list',
'snapshot-list',
'access-allow',
'access-deny',
'share-network-list',
'security-service-list',
)
)
self.assertFalse(wanted_commands - commands)
@ddt.data('admin', 'user')
def test_credentials(self, role):
self.clients[role].manila('credentials')
@ddt.data('admin', 'user')
def test_list_extensions(self, role):
roles = self.parser.listing(
self.clients[role].manila('list-extensions')
)
self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
@ddt.data('admin', 'user')
def test_endpoints(self, role):
self.clients[role].manila('endpoints')

View File

@@ -1,173 +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 uuidutils
from manilaclient.tests.functional import base
@ddt.ddt
class ExportLocationReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.share = self.create_share(client=self.get_user_client())
@ddt.data('admin', 'user')
def test_list_share_export_locations(self, role):
self.skip_if_microversion_not_supported('2.14')
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_export_locations(self.share['id'])
self.assertGreater(len(export_locations), 0)
expected_keys = ('ID', 'Path', 'Preferred')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['ID']))
self.assertIn(el['Preferred'], ('True', 'False'))
@ddt.data('admin', 'user')
def test_list_share_export_locations_with_columns(self, role):
self.skip_if_microversion_not_supported('2.9')
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_export_locations(
self.share['id'], columns='id,path'
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('Id', 'Path')
unexpected_keys = ('Updated At', 'Created At')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
for key in unexpected_keys:
self.assertNotIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['Id']))
@ddt.data('admin', 'user')
def test_get_share_export_location(self, role):
self.skip_if_microversion_not_supported('2.14')
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_export_locations(self.share['id'])
el = client.get_share_export_location(
self.share['id'], export_locations[0]['ID']
)
expected_keys = ['path', 'updated_at', 'created_at', 'id', 'preferred']
if role == 'admin':
expected_keys.extend(['is_admin_only', 'share_instance_id'])
for key in expected_keys:
self.assertIn(key, el)
if role == 'admin':
self.assertTrue(uuidutils.is_uuid_like(el['share_instance_id']))
self.assertIn(el['is_admin_only'], ('True', 'False'))
self.assertTrue(uuidutils.is_uuid_like(el['id']))
self.assertIn(el['preferred'], ('True', 'False'))
for list_k, get_k in (
('ID', 'id'),
('Path', 'path'),
('Preferred', 'preferred'),
):
self.assertEqual(export_locations[0][list_k], el[get_k])
def test_list_share_instance_export_locations(self):
self.skip_if_microversion_not_supported('2.14')
client = self.admin_client
share_instances = client.list_share_instances(self.share['id'])
self.assertGreater(len(share_instances), 0)
self.assertIn('ID', share_instances[0])
self.assertTrue(uuidutils.is_uuid_like(share_instances[0]['ID']))
share_instance_id = share_instances[0]['ID']
export_locations = client.list_share_instance_export_locations(
share_instance_id
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('ID', 'Path', 'Is Admin only', 'Preferred')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['ID']))
def test_list_share_instance_export_locations_with_columns(self):
self.skip_if_microversion_not_supported('2.9')
client = self.admin_client
share_instances = client.list_share_instances(self.share['id'])
self.assertGreater(len(share_instances), 0)
self.assertIn('ID', share_instances[0])
self.assertTrue(uuidutils.is_uuid_like(share_instances[0]['ID']))
share_instance_id = share_instances[0]['ID']
export_locations = client.list_share_instance_export_locations(
share_instance_id, columns='id,path'
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('Id', 'Path')
unexpected_keys = ('Updated At', 'Created At', 'Is Admin only')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
for key in unexpected_keys:
self.assertNotIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['Id']))
def test_get_share_instance_export_location(self):
self.skip_if_microversion_not_supported('2.14')
client = self.admin_client
share_instances = client.list_share_instances(self.share['id'])
self.assertGreater(len(share_instances), 0)
self.assertIn('ID', share_instances[0])
self.assertTrue(uuidutils.is_uuid_like(share_instances[0]['ID']))
share_instance_id = share_instances[0]['ID']
export_locations = client.list_share_instance_export_locations(
share_instance_id
)
el = client.get_share_instance_export_location(
share_instance_id, export_locations[0]['ID']
)
expected_keys = (
'path',
'updated_at',
'created_at',
'id',
'preferred',
'is_admin_only',
'share_instance_id',
)
for key in expected_keys:
self.assertIn(key, el)
self.assertIn(el['is_admin_only'], ('True', 'False'))
self.assertIn(el['preferred'], ('True', 'False'))
self.assertTrue(uuidutils.is_uuid_like(el['id']))
for list_k, get_k in (
('ID', 'id'),
('Path', 'path'),
('Preferred', 'preferred'),
('Is Admin only', 'is_admin_only'),
):
self.assertEqual(export_locations[0][list_k], el[get_k])

View File

@@ -1,29 +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 manilaclient.tests.functional import base
@ddt.ddt
class ManilaClientTestLimitsReadOnly(base.BaseTestCase):
@ddt.data('admin', 'user')
def test_rate_limits(self, role):
self.clients[role].manila('rate-limits')
@ddt.data('admin', 'user')
def test_absolute_limits(self, role):
self.clients[role].manila('absolute-limits')

View File

@@ -1,80 +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 manilaclient.tests.functional import base
@ddt.ddt
class MessagesReadOnlyTest(base.BaseTestCase):
@ddt.data(
("admin", "2.37"),
("user", "2.37"),
)
@ddt.unpack
def test_message_list(self, role, microversion):
self.skip_if_microversion_not_supported(microversion)
self.clients[role].manila("message-list", microversion=microversion)
@ddt.ddt
class MessagesReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.message = self.create_message()
def test_list_messages(self):
self.skip_if_microversion_not_supported('2.37')
messages = self.admin_client.list_messages()
self.assertTrue(any(m['ID'] is not None for m in messages))
self.assertTrue(any(m['User Message'] is not None for m in messages))
self.assertTrue(any(m['Resource ID'] is not None for m in messages))
self.assertTrue(any(m['Action ID'] is not None for m in messages))
self.assertTrue(any(m['Detail ID'] is not None for m in messages))
self.assertTrue(any(m['Resource Type'] is not None for m in messages))
@ddt.data(
'id',
'action_id',
'resource_id',
'action_id',
'detail_id',
'resource_type',
'created_at',
'action_id,detail_id,resource_id',
)
def test_list_share_type_select_column(self, columns):
self.skip_if_microversion_not_supported('2.37')
self.admin_client.list_messages(columns=columns)
def test_get_message(self):
self.skip_if_microversion_not_supported('2.37')
message = self.admin_client.get_message(self.message['ID'])
expected_keys = (
'id',
'action_id',
'resource_id',
'action_id',
'detail_id',
'resource_type',
'created_at',
'created_at',
)
for key in expected_keys:
self.assertIn(key, message)
def test_delete_message(self):
self.skip_if_microversion_not_supported('2.37')
message = self.create_message(cleanup_in_class=False)
self.admin_client.delete_message(message['ID'])
self.admin_client.wait_for_message_deletion(message['ID'])

View File

@@ -1,395 +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 random import randint
import ddt
from tempest.lib.cli import output_parser
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from manilaclient import api_versions
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
REPLICA_QUOTAS_MICROVERSION = '2.53'
def _get_share_type_quota_values(project_quota_value):
project_quota_value = int(project_quota_value)
if project_quota_value == -1:
return randint(1, 999)
elif project_quota_value == 0:
return 0
else:
return project_quota_value - 1
@ddt.ddt
@utils.skip_if_microversion_not_supported("2.39")
class QuotasReadWriteTest(base.BaseTestCase):
def setUp(self):
super(self.__class__, self).setUp()
self.microversion = "2.39"
self.project_id = self.admin_client.get_project_id(
self.admin_client.tenant_name
)
# Create share type
self.share_type = self.create_share_type(
name=data_utils.rand_name("manilaclient_functional_test"),
driver_handles_share_servers=False,
is_public=True,
microversion=self.microversion,
)
self.st_id = self.share_type["ID"]
def _verify_current_st_quotas_equal_to(self, quotas, microversion):
# Read share type quotas
cmd = (
f'quota-show --tenant-id {self.project_id} '
f'--share-type {self.st_id}'
)
st_quotas_raw = self.admin_client.manila(
cmd, microversion=microversion
)
st_quotas = output_parser.details(st_quotas_raw)
# Verify that quotas
self.assertGreater(len(st_quotas), 3)
for key, value in st_quotas.items():
if key not in (
'shares',
'gigabytes',
'snapshots',
'snapshot_gigabytes',
):
continue
self.assertIn(key, quotas)
self.assertEqual(int(quotas[key]), int(value))
def _verify_current_quotas_equal_to(self, quotas, microversion):
# Read quotas
cmd = f'quota-show --tenant-id {self.project_id}'
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
quotas = output_parser.details(quotas_raw)
# Verify that quotas
self.assertGreater(len(quotas), 3)
for key, value in quotas.items():
if key not in (
'shares',
'gigabytes',
'snapshots',
'snapshot_gigabytes',
'share_groups',
'share_group_snapshots',
):
continue
self.assertIn(key, quotas)
self.assertEqual(int(quotas[key]), int(value))
@ddt.data(
*set(
[
"2.40",
api_versions.MAX_VERSION,
]
)
)
def test_update_quotas_for_share_groups(self, microversion):
if not utils.is_microversion_supported(microversion):
msg = f"Microversion '{microversion}' not supported."
raise self.skipException(msg)
# Get default quotas
cmd = 'quota-defaults'
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
default_quotas = output_parser.details(quotas_raw)
# Get project quotas
cmd = f'quota-show --tenant-id {self.project_id} '
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
p_quotas = output_parser.details(quotas_raw)
# Define custom share group quotas for project
p_custom_quotas = {
'share_groups': -1 if int(p_quotas['share_groups']) != -1 else 999,
'share_group_snapshots': -1
if int(p_quotas['share_group_snapshots']) != -1
else 999,
}
# Update share group quotas for project
cmd = (
'quota-update {} --share-groups {} --share-group-snapshots {}'
).format(
self.project_id,
p_custom_quotas['share_groups'],
p_custom_quotas['share_group_snapshots'],
)
self.admin_client.manila(cmd, microversion=microversion)
# Verify quotas
self._verify_current_quotas_equal_to(p_custom_quotas, microversion)
# Reset quotas
cmd = (
f'quota-delete --tenant-id {self.project_id} '
f'--share-type {self.st_id}'
)
self.admin_client.manila(cmd, microversion=microversion)
# Verify quotas after reset
self._verify_current_quotas_equal_to(default_quotas, microversion)
# Return project quotas back
cmd = (
'quota-update {} --share-groups {} --share-group-snapshots {}'
).format(
self.project_id,
p_quotas['share_groups'],
p_quotas['share_group_snapshots'],
)
self.admin_client.manila(cmd, microversion=microversion)
# Verify quotas after reset
self._verify_current_quotas_equal_to(p_quotas, microversion)
@ddt.data('--share-groups', '--share-group-snapshots')
@utils.skip_if_microversion_not_supported("2.39")
def test_update_quotas_for_share_groups_using_too_old_microversion(
self, arg
):
cmd = f'quota-update {self.project_id} {arg} 13'
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.39',
)
@ddt.data('--share-replicas', '--replica-gigabytes')
@utils.skip_if_microversion_not_supported("2.52")
def test_update_quotas_for_share_replicas_using_too_old_microversion(
self, arg
):
cmd = f'quota-update {self.project_id} {arg} 10'
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.52',
)
@ddt.data('--share-groups', '--share-group-snapshots')
@utils.skip_if_microversion_not_supported("2.40")
def test_update_share_type_quotas_for_share_groups(self, arg):
cmd = (
f'quota-update {self.project_id} --share-type {self.st_id} '
f'{arg} 13'
)
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.40',
)
@ddt.data(
*set(
[
"2.39",
"2.40",
REPLICA_QUOTAS_MICROVERSION,
api_versions.MAX_VERSION,
]
)
)
def test_update_share_type_quotas_positive(self, microversion):
if not utils.is_microversion_supported(microversion):
msg = f"Microversion '{microversion}' not supported."
raise self.skipException(msg)
# Get project quotas
cmd = f'quota-show --tenant-id {self.project_id} '
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
p_quotas = output_parser.details(quotas_raw)
# Define share type quotas
st_custom_quotas = {
'shares': _get_share_type_quota_values(p_quotas['shares']),
'snapshots': _get_share_type_quota_values(p_quotas['snapshots']),
'gigabytes': _get_share_type_quota_values(p_quotas['gigabytes']),
'snapshot_gigabytes': _get_share_type_quota_values(
p_quotas['snapshot_gigabytes']
),
}
supports_share_replica_quotas = api_versions.APIVersion(
microversion
) >= api_versions.APIVersion(REPLICA_QUOTAS_MICROVERSION)
if supports_share_replica_quotas:
st_custom_quotas['share_replicas'] = _get_share_type_quota_values(
p_quotas['share_replicas']
)
st_custom_quotas['replica_gigabytes'] = (
_get_share_type_quota_values(p_quotas['replica_gigabytes'])
)
replica_params = (
' --share-replicas {} --replica-gigabytes {}'
).format(
st_custom_quotas['share_replicas'],
st_custom_quotas['replica_gigabytes'],
)
# Update quotas for share type
cmd = (
'quota-update {} --share-type {} '
'--shares {} --gigabytes {} --snapshots {} '
'--snapshot-gigabytes {}'
).format(
self.project_id,
self.st_id,
st_custom_quotas['shares'],
st_custom_quotas['gigabytes'],
st_custom_quotas['snapshots'],
st_custom_quotas['snapshot_gigabytes'],
)
if supports_share_replica_quotas:
cmd += replica_params
self.admin_client.manila(cmd, microversion=microversion)
# Verify share type quotas
self._verify_current_st_quotas_equal_to(st_custom_quotas, microversion)
# Reset share type quotas
cmd = (
f'quota-delete --tenant-id {self.project_id} '
f'--share-type {self.st_id}'
)
self.admin_client.manila(cmd, microversion=microversion)
# Verify share type quotas after reset
self._verify_current_st_quotas_equal_to(p_quotas, microversion)
@utils.skip_if_microversion_not_supported("2.38")
def test_read_share_type_quotas_with_too_old_microversion(self):
cmd = (
f'quota-show --tenant-id {self.project_id} '
f'--share-type {self.st_id}'
)
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.38',
)
@utils.skip_if_microversion_not_supported("2.38")
def test_update_share_type_quotas_with_too_old_microversion(self):
cmd = 'quota-update --tenant-id {} --share-type {} --shares {}'.format(
self.project_id, self.st_id, '0'
)
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.38',
)
@utils.skip_if_microversion_not_supported("2.38")
def test_delete_share_type_quotas_with_too_old_microversion(self):
cmd = (
f'quota-delete --tenant-id {self.project_id} '
f'--share-type {self.st_id}'
)
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.manila,
cmd,
microversion='2.38',
)
@ddt.ddt
class ManilaClientTestQuotasReadOnly(base.BaseTestCase):
def test_quota_class_show_by_admin(self):
roles = self.parser.listing(
self.clients['admin'].manila('quota-class-show', params='abc')
)
self.assertTableStruct(roles, ('Property', 'Value'))
def test_quota_class_show_by_user(self):
self.assertRaises(
exceptions.CommandFailed,
self.clients['user'].manila,
'quota-class-show',
params='abc',
)
def _get_quotas(self, role, operation, microversion):
roles = self.parser.listing(
self.clients[role].manila(
f'quota-{operation}', microversion=microversion
)
)
self.assertTableStruct(roles, ('Property', 'Value'))
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("1.0")
def test_quota_defaults_api_1_0(self, role):
self._get_quotas(role, "defaults", "1.0")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.0")
def test_quota_defaults_api_2_0(self, role):
self._get_quotas(role, "defaults", "2.0")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.6")
def test_quota_defaults_api_2_6(self, role):
self._get_quotas(role, "defaults", "2.6")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.7")
def test_quota_defaults_api_2_7(self, role):
self._get_quotas(role, "defaults", "2.7")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("1.0")
def test_quota_show_api_1_0(self, role):
self._get_quotas(role, "show", "1.0")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.0")
def test_quota_show_api_2_0(self, role):
self._get_quotas(role, "show", "2.0")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.6")
def test_quota_show_api_2_6(self, role):
self._get_quotas(role, "show", "2.6")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.7")
def test_quota_show_api_2_7(self, role):
self._get_quotas(role, "show", "2.7")
@ddt.data('admin', 'user')
@utils.skip_if_microversion_not_supported("2.25")
def test_quota_show_api_2_25(self, role):
self._get_quotas(role, "show --detail", "2.25")

View File

@@ -1,49 +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.
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from manilaclient.tests.functional import base
class ManilaClientTestSchedulerStatsReadOnly(base.BaseTestCase):
def test_pools_list(self):
self.clients['admin'].manila('pool-list')
def test_pools_list_with_debug_flag(self):
self.clients['admin'].manila('pool-list', flags='--debug')
def test_pools_list_with_detail(self):
self.clients['admin'].manila('pool-list', params='--detail')
def test_pools_list_with_share_type_filter(self):
share_type = self.create_share_type(
name=data_utils.rand_name('manilaclient_functional_test'),
snapshot_support=True,
)
self.clients['admin'].manila(
'pool-list', params='--share_type ' + share_type['ID']
)
def test_pools_list_with_filters(self):
self.clients['admin'].manila(
'pool-list',
params='--host myhost --backend mybackend --pool mypool',
)
def test_pools_list_by_user(self):
self.assertRaises(
exceptions.CommandFailed, self.clients['user'].manila, 'pool-list'
)

View File

@@ -1,80 +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.lib.common.utils import data_utils
from manilaclient.tests.functional import base
@ddt.ddt
class SecurityServiceReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.name = data_utils.rand_name('autotest')
self.description = 'fake_description'
self.user = 'fake_user'
self.password = 'fake_password'
self.server = 'fake_server'
self.domain = 'fake_domain'
self.dns_ip = '1.2.3.4'
self.ou = 'fake_ou'
self.default_ad_site = 'fake_default_ad_site'
@ddt.data(
{'name': 'test_name'},
{'description': 'test_description'},
{'user': 'test_username'},
{'password': 'test_password'},
{'server': 'test_server'},
{'default_ad_site': 'test_default_ad_site'},
{'domain': 'test_domain'},
{'dns_ip': 'test_dns_ip'},
{'ou': 'test_ou'},
{'name': '""'},
{'description': '""'},
{'user': '""'},
{'password': '""'},
{'server': '""'},
{'default_ad_site': '""'},
{'domain': '""'},
{'dns_ip': '""'},
{'ou': '""'},
)
def test_create_update_security_service(self, ss_data):
expected_data = {
'name': self.name,
'description': self.description,
'user': self.user,
'password': self.password,
'server': self.server,
'domain': self.domain,
'dns_ip': self.dns_ip,
'ou': self.ou,
}
if 'default_ad_site' in ss_data:
expected_data.pop('server')
expected_data['default_ad_site'] = self.default_ad_site
ss = self.create_security_service(**expected_data)
update = self.admin_client.update_security_service(ss['id'], **ss_data)
expected_data.update(ss_data)
for k, v in expected_data.items():
if v == '""':
self.assertEqual('None', update[k])
else:
self.assertEqual(v, update[k])

View File

@@ -1,44 +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 manilaclient.tests.functional import base
@ddt.ddt
class ManilaClientTestServicesReadOnly(base.BaseTestCase):
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_services_list(self, microversion):
self.skip_if_microversion_not_supported(microversion)
self.admin_client.manila('service-list', microversion=microversion)
def test_list_with_debug_flag(self):
self.clients['admin'].manila('service-list', flags='--debug')
def test_shares_list_filter_by_host(self):
self.clients['admin'].manila('service-list', params='--host host')
def test_shares_list_filter_by_binary(self):
self.clients['admin'].manila('service-list', params='--binary binary')
def test_shares_list_filter_by_zone(self):
self.clients['admin'].manila('service-list', params='--zone zone')
def test_shares_list_filter_by_status(self):
self.clients['admin'].manila('service-list', params='--status status')
def test_shares_list_filter_by_state(self):
self.clients['admin'].manila('service-list', params='--state state')

View File

@@ -1,384 +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 ast
import ddt
from tempest.lib import exceptions as tempest_lib_exc
from manilaclient import api_versions
from manilaclient import config
from manilaclient.tests.functional import base
CONF = config.CONF
@ddt.ddt
class ShareAccessReadWriteBase(base.BaseTestCase):
protocol = None
access_level = None
def setUp(self):
super().setUp()
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled."
raise self.skipException(message)
if self.access_level not in CONF.access_levels_mapping.get(
self.protocol, ''
).split(' '):
raise self.skipException(
f"{self.access_level} tests for {self.protocol} share "
"access are disabled."
)
self.access_types = CONF.access_types_mapping.get(
self.protocol, ''
).split(' ')
if not self.access_types:
raise self.skipException(
f"No access levels were provided for {self.protocol} "
"share access tests."
)
self.share = self.create_share(
share_protocol=self.protocol, public=True
)
self.share_id = self.share['id']
# NOTE(vponomaryov): increase following int range when significant
# amount of new tests is added.
int_range = range(20, 50)
self.access_to = {
# NOTE(vponomaryov): list of unique values is required for ability
# to create lots of access rules for one share using different
# API microversions.
'ip': [f'99.88.77.{i}' for i in int_range],
# NOTE(vponomaryov): following users are fakes and access rules
# that use it are expected to fail, but they are used only for
# API testing.
'user': [f'foo_user_{i}' for i in int_range],
'cert': [f'tenant_{i}.example.com' for i in int_range],
'ipv6': [f'2001:db8::{i}' for i in int_range],
}
def _test_create_list_access_rule_for_share(
self, microversion, metadata=None
):
access_type = self.access_types[0]
access = self.user_client.access_allow(
self.share['id'],
access_type,
self.access_to[access_type].pop(),
self.access_level,
metadata=metadata,
microversion=microversion,
)
return access
@ddt.data(
*set(
[
"1.0",
"2.0",
"2.6",
"2.7",
"2.21",
"2.33",
"2.44",
"2.45",
api_versions.MAX_VERSION,
]
)
)
def test_create_list_access_rule_for_share(self, microversion):
self.skip_if_microversion_not_supported(microversion)
access = self._test_create_list_access_rule_for_share(
microversion=microversion
)
access_list = self.user_client.list_access(
self.share['id'], microversion=microversion
)
self.assertTrue(
any([item for item in access_list if access['id'] == item['id']])
)
self.assertTrue(any(a['access_type'] is not None for a in access_list))
self.assertTrue(any(a['access_to'] is not None for a in access_list))
self.assertTrue(
any(a['access_level'] is not None for a in access_list)
)
if api_versions.APIVersion(microversion) >= api_versions.APIVersion(
"2.33"
):
self.assertTrue(
all(
all(
key in access
for key in ('access_key', 'created_at', 'updated_at')
)
for access in access_list
)
)
elif api_versions.APIVersion(microversion) >= api_versions.APIVersion(
"2.21"
):
self.assertTrue(all('access_key' in a for a in access_list))
else:
self.assertTrue(all('access_key' not in a for a in access_list))
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_create_list_access_rule_for_share_select_column(
self, microversion
):
self.skip_if_microversion_not_supported(microversion)
self._test_create_list_access_rule_for_share(microversion=microversion)
access_list = self.user_client.list_access(
self.share['id'],
columns="access_type,access_to",
microversion=microversion,
)
self.assertTrue(any(a['Access_Type'] is not None for a in access_list))
self.assertTrue(any(a['Access_To'] is not None for a in access_list))
self.assertTrue(all('Access_Level' not in a for a in access_list))
self.assertTrue(all('access_level' not in a for a in access_list))
def _create_delete_access_rule(
self, share_id, access_type, access_to, microversion=None
):
self.skip_if_microversion_not_supported(microversion)
if access_type not in self.access_types:
raise self.skipException(
f"'{access_type}' access rules is disabled for protocol "
f"'{self.protocol}'."
)
access = self.user_client.access_allow(
share_id,
access_type,
access_to,
self.access_level,
microversion=microversion,
)
self.assertEqual(share_id, access.get('share_id'))
self.assertEqual(access_type, access.get('access_type'))
self.assertEqual(
access_to.replace('\\\\', '\\'), access.get('access_to')
)
self.assertEqual(self.access_level, access.get('access_level'))
if api_versions.APIVersion(microversion) >= api_versions.APIVersion(
"2.33"
):
self.assertIn('access_key', access)
self.assertIn('created_at', access)
self.assertIn('updated_at', access)
elif api_versions.APIVersion(microversion) >= api_versions.APIVersion(
"2.21"
):
self.assertIn('access_key', access)
else:
self.assertNotIn('access_key', access)
self.user_client.wait_for_access_rule_status(share_id, access['id'])
self.user_client.access_deny(share_id, access['id'])
self.user_client.wait_for_access_rule_deletion(share_id, access['id'])
self.assertRaises(
tempest_lib_exc.NotFound,
self.user_client.get_access,
share_id,
access['id'],
)
@ddt.data(*set(["2.45", api_versions.MAX_VERSION]))
def test_create_list_access_rule_with_metadata(self, microversion):
self.skip_if_microversion_not_supported(microversion)
md1 = {"key1": "value1", "key2": "value2"}
md2 = {"key3": "value3", "key4": "value4"}
self._test_create_list_access_rule_for_share(
metadata=md1, microversion=microversion
)
access = self._test_create_list_access_rule_for_share(
metadata=md2, microversion=microversion
)
access_list = self.user_client.list_access(
self.share['id'],
metadata={"key4": "value4"},
microversion=microversion,
)
self.assertEqual(1, len(access_list))
# Verify share metadata
get_access = self.user_client.access_show(
access_list[0]['id'], microversion=microversion
)
metadata = ast.literal_eval(get_access['metadata'])
self.assertEqual(2, len(metadata))
self.assertIn('key3', metadata)
self.assertIn('key4', metadata)
self.assertEqual(md2['key3'], metadata['key3'])
self.assertEqual(md2['key4'], metadata['key4'])
self.assertEqual(access['id'], access_list[0]['id'])
self.user_client.access_deny(access['share_id'], access['id'])
self.user_client.wait_for_access_rule_deletion(
access['share_id'], access['id']
)
@ddt.data(*set(["2.45", api_versions.MAX_VERSION]))
def test_create_update_show_access_rule_with_metadata(self, microversion):
self.skip_if_microversion_not_supported(microversion)
md1 = {"key1": "value1", "key2": "value2"}
md2 = {"key3": "value3", "key2": "value4"}
# create a access rule with metadata
access = self._test_create_list_access_rule_for_share(
metadata=md1, microversion=microversion
)
# get the access rule
get_access = self.user_client.access_show(
access['id'], microversion=microversion
)
# verify access rule
self.assertEqual(access['id'], get_access['id'])
self.assertEqual(md1, ast.literal_eval(get_access['metadata']))
# update access rule metadata
self.user_client.access_set_metadata(
access['id'], metadata=md2, microversion=microversion
)
get_access = self.user_client.access_show(
access['id'], microversion=microversion
)
# verify access rule after update access rule metadata
self.assertEqual(
{"key1": "value1", "key2": "value4", "key3": "value3"},
ast.literal_eval(get_access['metadata']),
)
self.assertEqual(access['id'], get_access['id'])
@ddt.data(*set(["2.45", api_versions.MAX_VERSION]))
def test_delete_access_rule_metadata(self, microversion):
self.skip_if_microversion_not_supported(microversion)
md = {"key1": "value1", "key2": "value2"}
# create a access rule with metadata
access = self._test_create_list_access_rule_for_share(
metadata=md, microversion=microversion
)
# get the access rule
get_access = self.user_client.access_show(
access['id'], microversion=microversion
)
# verify access rule
self.assertEqual(access['id'], get_access['id'])
self.assertEqual(md, ast.literal_eval(get_access['metadata']))
# delete access rule metadata
self.user_client.access_unset_metadata(
access['id'], keys=["key1", "key2"], microversion=microversion
)
get_access = self.user_client.access_show(
access['id'], microversion=microversion
)
# verify access rule after delete access rule metadata
self.assertEqual({}, ast.literal_eval(get_access['metadata']))
self.assertEqual(access['id'], get_access['id'])
@ddt.data("1.0", "2.0", "2.6", "2.7", "2.21", "2.33")
def test_create_delete_ip_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'ip', self.access_to['ip'].pop(), microversion
)
@ddt.data("1.0", "2.0", "2.6", "2.7", "2.21", "2.33")
def test_create_delete_user_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'user', CONF.username_for_user_rules, microversion
)
@ddt.data("1.0", "2.0", "2.6", "2.7", "2.21", "2.33")
def test_create_delete_cert_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'cert', self.access_to['cert'].pop(), microversion
)
@ddt.data("2.38", api_versions.MAX_VERSION)
def test_create_delete_ipv6_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'ip', self.access_to['ipv6'].pop(), microversion
)
class NFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'nfs'
access_level = 'rw'
class NFSShareROAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'nfs'
access_level = 'ro'
class CIFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'cifs'
access_level = 'rw'
class CIFSShareROAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'cifs'
access_level = 'ro'
class GlusterFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'glusterfs'
access_level = 'rw'
class GlusterFSShareROAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'glusterfs'
access_level = 'ro'
class HDFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'hdfs'
access_level = 'rw'
class HDFSShareROAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'hdfs'
access_level = 'ro'
class MAPRFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'maprfs'
access_level = 'rw'
class MAPRFSShareROAccessReadWriteTest(ShareAccessReadWriteBase):
protocol = 'maprfs'
access_level = 'ro'
def load_tests(loader, tests, _):
result = []
for test_case in tests:
if type(test_case._tests[0]) is ShareAccessReadWriteBase:
continue
result.append(test_case)
return loader.suiteClass(result)

View File

@@ -1,129 +0,0 @@
# Copyright 2019 NetApp
# 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 manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
@ddt.ddt
@utils.skip_if_microversion_not_supported('2.51')
class ShareNetworkSubnetsReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.name = data_utils.rand_name('autotest')
self.description = 'fake_description'
self.neutron_net_id = 'fake_neutron_net_id'
self.neutron_subnet_id = 'fake_neutron_subnet_id'
self.sn = self.create_share_network(
name=self.name,
description=self.description,
neutron_net_id=self.neutron_net_id,
neutron_subnet_id=self.neutron_subnet_id,
)
def test_get_share_network_subnet(self):
default_subnet = utils.get_default_subnet(
self.user_client, self.sn['id']
)
subnet = self.user_client.get_share_network_subnet(
self.sn['id'], default_subnet['id']
)
self.assertEqual(self.neutron_net_id, subnet['neutron_net_id'])
self.assertEqual(self.neutron_subnet_id, subnet['neutron_subnet_id'])
def test_get_invalid_share_network_subnet(self):
self.assertRaises(
exceptions.CommandFailed,
self.user_client.get_share_network_subnet,
self.sn['id'],
'invalid_subnet_id',
)
def _get_availability_zone(self):
availability_zones = self.user_client.list_availability_zones()
return availability_zones[0]['Name']
def test_add_share_network_subnet_to_share_network(self):
neutron_net_id = 'new_neutron_net_id'
neutron_subnet_id = 'new_neutron_subnet_id'
availability_zone = self._get_availability_zone()
subnet = self.add_share_network_subnet(
self.sn['id'],
neutron_net_id,
neutron_subnet_id,
availability_zone,
cleanup_in_class=False,
)
self.assertEqual(neutron_net_id, subnet['neutron_net_id'])
self.assertEqual(neutron_subnet_id, subnet['neutron_subnet_id'])
self.assertEqual(availability_zone, subnet['availability_zone'])
@ddt.data(
{'neutron_net_id': None, 'neutron_subnet_id': 'fake_subnet_id'},
{'neutron_net_id': 'fake_net_id', 'neutron_subnet_id': None},
{'availability_zone': 'invalid_availability_zone'},
)
def test_add_invalid_share_network_subnet_to_share_network(self, params):
self.assertRaises(
exceptions.CommandFailed,
self.add_share_network_subnet,
self.sn['id'],
**params,
)
def test_add_share_network_subnet_to_invalid_share_network(self):
self.assertRaises(
exceptions.CommandFailed,
self.add_share_network_subnet,
'invalid_share_network',
self.neutron_net_id,
self.neutron_subnet_id,
)
def test_add_delete_share_network_subnet_from_share_network(self):
neutron_net_id = 'new_neutron_net_id'
neutron_subnet_id = 'new_neutron_subnet_id'
availability_zone = self._get_availability_zone()
subnet = self.add_share_network_subnet(
self.sn['id'],
neutron_net_id,
neutron_subnet_id,
availability_zone,
cleanup_in_class=False,
)
self.user_client.delete_share_network_subnet(
share_network_subnet=subnet['id'], share_network=self.sn['id']
)
self.user_client.wait_for_share_network_subnet_deletion(
share_network_subnet=subnet['id'], share_network=self.sn['id']
)
def test_delete_invalid_share_network_subnet(self):
self.assertRaises(
exceptions.NotFound,
self.user_client.delete_share_network_subnet,
share_network_subnet='invalid_subnet_id',
share_network=self.sn['id'],
)

View File

@@ -1,695 +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 ast
import ddt
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as tempest_lib_exc
import time
from manilaclient import config
from manilaclient import exceptions
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
SECURITY_SERVICE_UPDATE_VERSION = '2.63'
CONF = config.CONF
@ddt.ddt
class ShareNetworksReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.name = data_utils.rand_name('autotest')
self.description = 'fake_description'
self.neutron_net_id = 'fake_neutron_net_id'
self.neutron_subnet_id = 'fake_neutron_subnet_id'
self.sn = self.create_share_network(
name=self.name,
description=self.description,
neutron_net_id=self.neutron_net_id,
neutron_subnet_id=self.neutron_subnet_id,
)
@ddt.data(
{'name': data_utils.rand_name('autotest_share_network_name')},
{'description': 'fake_description'},
{
'neutron_net_id': 'fake_neutron_net_id',
'neutron_subnet_id': 'fake_neutron_subnet_id',
},
)
def test_create_delete_share_network(self, net_data):
share_subnet_support = utils.share_network_subnets_are_supported()
share_subnet_fields = (
['neutron_net_id', 'neutron_subnet_id', 'availability_zone']
if share_subnet_support
else []
)
sn = self.create_share_network(cleanup_in_class=False, **net_data)
default_subnet = (
utils.get_default_subnet(self.user_client, sn['id'])
if share_subnet_support
else None
)
expected_data = {
'name': 'None',
'description': 'None',
'neutron_net_id': 'None',
'neutron_subnet_id': 'None',
}
expected_data.update(net_data)
share_network_expected_data = [
(k, v)
for k, v in expected_data.items()
if k not in share_subnet_fields
]
share_subnet_expected_data = [
(k, v)
for k, v in expected_data.items()
if k in share_subnet_fields
]
for k, v in share_network_expected_data:
self.assertEqual(v, sn[k])
for k, v in share_subnet_expected_data:
self.assertEqual(v, default_subnet[k])
self.admin_client.delete_share_network(sn['id'])
self.admin_client.wait_for_share_network_deletion(sn['id'])
@utils.skip_if_microversion_not_supported('2.51')
def test_create_delete_share_network_with_az(self):
share_subnet_fields = [
'neutron_net_id',
'neutron_subnet_id',
'availability_zone',
]
az = self.user_client.list_availability_zones()[0]
net_data = {
'neutron_net_id': 'fake_neutron_net_id',
'neutron_subnet_id': 'fake_neutron_subnet_id',
'availability_zone': az['Name'],
}
sn = self.create_share_network(cleanup_in_class=False, **net_data)
default_subnet = utils.get_subnet_by_availability_zone_name(
self.user_client, sn['id'], az['Name']
)
expected_data = {
'name': 'None',
'description': 'None',
'neutron_net_id': 'None',
'neutron_subnet_id': 'None',
'availability_zone': 'None',
}
expected_data.update(net_data)
share_network_expected_data = [
(k, v)
for k, v in expected_data.items()
if k not in share_subnet_fields
]
share_subnet_expected_data = [
(k, v)
for k, v in expected_data.items()
if k in share_subnet_fields
]
for k, v in share_network_expected_data:
self.assertEqual(v, sn[k])
for k, v in share_subnet_expected_data:
self.assertEqual(v, default_subnet[k])
self.admin_client.delete_share_network(sn['id'])
self.admin_client.wait_for_share_network_deletion(sn['id'])
def test_get_share_network_with_neutron_data(self):
get = self.admin_client.get_share_network(self.sn['id'])
self.assertEqual(self.name, get['name'])
self.assertEqual(self.description, get['description'])
if not utils.share_network_subnets_are_supported():
self.assertEqual(self.neutron_net_id, get['neutron_net_id'])
self.assertEqual(self.neutron_subnet_id, get['neutron_subnet_id'])
def _get_expected_update_data(self, net_data, net_creation_data):
# NOTE(dviroel): When subnets are supported, the outputs are converted
# from string to literal structures in order to process the content of
# 'share_network_subnets' field.
default_return_value = (
None if utils.share_network_subnets_are_supported() else 'None'
)
expected_nn_id = (
default_return_value
if net_data.get('neutron_net_id')
else net_creation_data.get('neutron_net_id', default_return_value)
)
expected_nsn_id = (
default_return_value
if net_data.get('neutron_subnet_id')
else net_creation_data.get(
'neutron_subnet_id', default_return_value
)
)
return expected_nn_id, expected_nsn_id
@ddt.data(
({'name': data_utils.rand_name('autotest_share_network_name')}, {}),
({'description': 'fake_description'}, {}),
(
{
'neutron_net_id': 'fake_neutron_net_id',
'neutron_subnet_id': 'fake_neutron_subnet_id',
},
{},
),
({'name': '""'}, {}),
({'description': '""'}, {}),
(
{'neutron_net_id': '""'},
{
'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_nsn_id',
},
),
(
{'neutron_subnet_id': '""'},
{
'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_nsn_id',
},
),
)
@ddt.unpack
def test_create_update_share_network(self, net_data, net_creation_data):
sn = self.create_share_network(
cleanup_in_class=False, **net_creation_data
)
update = self.admin_client.update_share_network(sn['id'], **net_data)
expected_nn_id, expected_nsn_id = self._get_expected_update_data(
net_data, net_creation_data
)
expected_data = {
'name': 'None',
'description': 'None',
'neutron_net_id': expected_nn_id,
'neutron_subnet_id': expected_nsn_id,
}
subnet_keys = []
if utils.share_network_subnets_are_supported():
subnet_keys = ['neutron_net_id', 'neutron_subnet_id']
subnet = ast.literal_eval(update['share_network_subnets'])
update_values = dict(
[(k, v) for k, v in net_data.items() if v != '""']
)
expected_data.update(update_values)
for k, v in expected_data.items():
if k in subnet_keys:
self.assertEqual(v, subnet[0][k])
else:
self.assertEqual(v, update[k])
self.admin_client.delete_share_network(sn['id'])
self.admin_client.wait_for_share_network_deletion(sn['id'])
@ddt.data(True, False)
def test_list_share_networks(self, all_tenants):
share_networks = self.admin_client.list_share_networks(all_tenants)
self.assertTrue(
any(self.sn['id'] == sn['id'] for sn in share_networks)
)
for sn in share_networks:
self.assertEqual(2, len(sn))
self.assertIn('id', sn)
self.assertIn('name', sn)
def test_list_share_networks_select_column(self):
share_networks = self.admin_client.list_share_networks(columns="id")
self.assertTrue(any(s['Id'] is not None for s in share_networks))
self.assertTrue(all('Name' not in s for s in share_networks))
self.assertTrue(all('name' not in s for s in share_networks))
def _list_share_networks_with_filters(self, filters):
assert_subnet_fields = utils.share_network_subnets_are_supported()
share_subnet_fields = (
['neutron_subnet_id', 'neutron_net_id']
if assert_subnet_fields
else []
)
share_network_filters = [
(k, v) for k, v in filters.items() if k not in share_subnet_fields
]
share_network_subnet_filters = [
(k, v) for k, v in filters.items() if k in share_subnet_fields
]
share_networks = self.admin_client.list_share_networks(filters=filters)
self.assertGreater(len(share_networks), 0)
self.assertTrue(
any(self.sn['id'] == sn['id'] for sn in share_networks)
)
for sn in share_networks:
try:
share_network = self.admin_client.get_share_network(sn['id'])
default_subnet = (
utils.get_default_subnet(self.user_client, sn['id'])
if assert_subnet_fields
else None
)
except tempest_lib_exc.NotFound:
# NOTE(vponomaryov): Case when some share network was deleted
# between our 'list' and 'get' requests. Skip such case.
continue
for k, v in share_network_filters:
self.assertIn(k, share_network)
self.assertEqual(v, share_network[k])
for k, v in share_network_subnet_filters:
self.assertIn(k, default_subnet)
self.assertEqual(v, default_subnet[k])
def test_list_share_networks_filter_by_project_id(self):
project_id = self.admin_client.get_project_id(
self.admin_client.tenant_name
)
filters = {'project_id': project_id}
self._list_share_networks_with_filters(filters)
def test_list_share_networks_filter_by_name(self):
filters = {'name': self.name}
self._list_share_networks_with_filters(filters)
def test_list_share_networks_filter_by_description(self):
filters = {'description': self.description}
self._list_share_networks_with_filters(filters)
def test_list_share_networks_filter_by_neutron_net_id(self):
filters = {'neutron_net_id': self.neutron_net_id}
self._list_share_networks_with_filters(filters)
def test_list_share_networks_filter_by_neutron_subnet_id(self):
filters = {'neutron_subnet_id': self.neutron_subnet_id}
self._list_share_networks_with_filters(filters)
@ddt.data('name', 'description')
def test_list_share_networks_filter_by_inexact(self, option):
self.create_share_network(
name=data_utils.rand_name('autotest_inexact'),
description='fake_description_inexact',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
filters = {option + '~': 'inexact'}
share_networks = self.admin_client.list_share_networks(filters=filters)
self.assertGreater(len(share_networks), 0)
def test_list_share_networks_by_inexact_unicode_option(self):
self.create_share_network(
name='网络名称',
description='网络描述',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
filters = {'name~': '名称'}
share_networks = self.admin_client.list_share_networks(filters=filters)
self.assertGreater(len(share_networks), 0)
filters = {'description~': '描述'}
share_networks = self.admin_client.list_share_networks(filters=filters)
self.assertGreater(len(share_networks), 0)
def test_share_network_reset_status(self):
share_network = self.create_share_network(
client=self.user_client,
name='cool_net_name',
description='fakedescription',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
# Admin operation
self.admin_client.share_network_reset_state(
share_network['id'],
'error',
microversion=SECURITY_SERVICE_UPDATE_VERSION,
)
self.user_client.wait_for_resource_status(
share_network['id'],
'error',
microversion=SECURITY_SERVICE_UPDATE_VERSION,
resource_type="share_network",
)
def test_share_network_security_service_add(self):
share_network = self.create_share_network(
client=self.user_client,
name='cool_net_name',
description='fakedescription',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
new_security_service = self.create_security_service(
client=self.user_client
)
check_result = (
self.user_client.share_network_security_service_add_check(
share_network['id'],
security_service_id=new_security_service['id'],
)
)
self.assertEqual(check_result['compatible'], 'True')
self.user_client.share_network_security_service_add(
share_network['id'], new_security_service['id']
)
network_services = (
self.user_client.share_network_security_service_list(
share_network['id']
)
)
self.assertEqual(len(network_services), 1)
self.assertEqual(network_services[0]['id'], new_security_service['id'])
def test_share_network_security_service_update(self):
share_network = self.create_share_network(
client=self.user_client,
name='cool_net_name',
description='fakedescription',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
current_name = 'current'
new_name = 'new'
current_security_service = self.create_security_service(
client=self.user_client, name=current_name
)
new_security_service = self.create_security_service(
client=self.user_client, name=new_name
)
check_result = (
self.user_client.share_network_security_service_add_check(
share_network['id'], current_security_service['id']
)
)
self.assertEqual(check_result['compatible'], 'True')
self.user_client.share_network_security_service_add(
share_network['id'], current_security_service['id']
)
network_services = (
self.user_client.share_network_security_service_list(
share_network['id']
)
)
self.assertEqual(len(network_services), 1)
self.assertEqual(network_services[0]['name'], current_name)
check_result = (
self.user_client.share_network_security_service_update_check(
share_network['id'],
current_security_service['id'],
new_security_service['id'],
)
)
self.assertEqual(check_result['compatible'], 'True')
self.user_client.share_network_security_service_update(
share_network['id'],
current_security_service['id'],
new_security_service['id'],
)
network_services = (
self.user_client.share_network_security_service_list(
share_network['id']
)
)
self.assertEqual(len(network_services), 1)
self.assertEqual(network_services[0]['name'], new_name)
def test_share_network_subnet_create_check(self):
share_network = self.create_share_network(
client=self.user_client,
description='fakedescription',
)
check_result = self.user_client.share_network_subnet_create_check(
share_network['id'],
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
self.assertEqual(check_result['compatible'], 'True')
@ddt.data(
{'neutron_net_id': None, 'neutron_subnet_id': 'fake_subnet_id'},
{'neutron_net_id': 'fake_net_id', 'neutron_subnet_id': None},
{'availability_zone': 'invalid_availability_zone'},
)
def test_check_add_share_network_subnet_with_invalid_params(self, params):
self.assertRaises(
tempest_lib_exc.CommandFailed,
self.user_client.share_network_subnet_create_check,
self.sn['id'],
**params,
)
def test_check_add_share_network_subnet_to_invalid_share_network(self):
self.assertRaises(
tempest_lib_exc.CommandFailed,
self.user_client.share_network_subnet_create_check,
'invalid_share_network',
self.neutron_net_id,
self.neutron_subnet_id,
)
class ShareNetworkSecurityServiceCheckReadWriteTests(base.BaseTestCase):
protocol = None
def setUp(self):
super().setUp()
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled."
raise self.skipException(message)
self.client = self.get_user_client()
if not self.client.share_network:
message = "Can run only with DHSS=True mode"
raise self.skipException(message)
def _wait_for_update_security_service_compatible_result(
self,
share_network,
current_security_service,
new_security_service=None,
):
compatible_expected_result = 'True'
check_is_compatible = 'None'
tentatives = 0
# There might be a delay from the time the check is requested until
# the backend has performed all checks
while check_is_compatible != compatible_expected_result:
tentatives += 1
if not new_security_service:
check_is_compatible = (
self.user_client.share_network_security_service_add_check(
share_network['id'], current_security_service['id']
)
)['compatible']
else:
check_is_compatible = (
self.user_client.share_network_security_service_update_check(
share_network['id'],
current_security_service['id'],
new_security_service['id'],
)
)['compatible']
if tentatives > 3:
timeout_message = (
"Share network security service add/update check did not "
"reach 'compatible=True' within 15 seconds."
)
raise exceptions.TimeoutException(message=timeout_message)
time.sleep(5)
def test_check_if_security_service_can_be_added_to_share_network_in_use(
self,
):
share_network = self.create_share_network(
client=self.user_client,
description='fakedescription',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
# Create a share so we can be sure that a share server will exist and
# the check will be performed in the backends
self.create_share(
self.protocol,
client=self.user_client,
share_network=share_network['id'],
)
current_security_service = self.create_security_service(
client=self.user_client
)
check_result = (
self.user_client.share_network_security_service_add_check(
share_network['id'], current_security_service['id']
)
)
self.assertEqual(check_result['compatible'], 'None')
self._wait_for_update_security_service_compatible_result(
share_network, current_security_service
)
def test_add_and_update_security_service_when_share_network_is_in_use(
self,
):
share_network = self.create_share_network(
client=self.user_client,
name='cool_net_name',
description='fakedescription',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
)
# Create a share so we can be sure that a share server will exist and
# the check will be performed in the backends
self.create_share(
self.protocol,
name='fake_share_name',
share_network=share_network['id'],
client=self.user_client,
)
current_security_service = self.create_security_service(
client=self.user_client, name='current_security_service'
)
new_security_service = self.create_security_service(
client=self.user_client, name='new_security_service'
)
check_result = (
self.user_client.share_network_security_service_add_check(
share_network['id'], current_security_service['id']
)
)
self.assertEqual(check_result['compatible'], 'None')
self._wait_for_update_security_service_compatible_result(
share_network, current_security_service
)
self.user_client.share_network_security_service_add(
share_network['id'], current_security_service['id']
)
network_services = (
self.user_client.share_network_security_service_list(
share_network['id']
)
)
self.assertEqual(len(network_services), 1)
self.assertEqual(
network_services[0]['name'], current_security_service['name']
)
self.user_client.wait_for_resource_status(
share_network['id'],
'active',
microversion=SECURITY_SERVICE_UPDATE_VERSION,
resource_type="share_network",
)
check_result = (
self.user_client.share_network_security_service_update_check(
share_network['id'],
current_security_service['id'],
new_security_service['id'],
)
)
self.assertEqual(check_result['compatible'], 'None')
self._wait_for_update_security_service_compatible_result(
share_network,
current_security_service,
new_security_service=new_security_service,
)
self.user_client.share_network_security_service_update(
share_network['id'],
current_security_service['id'],
new_security_service['id'],
)
network_services = (
self.user_client.share_network_security_service_list(
share_network['id']
)
)
self.assertEqual(len(network_services), 1)
self.assertEqual(
network_services[0]['name'], new_security_service['name']
)
self.user_client.wait_for_resource_status(
share_network['id'],
'active',
microversion=SECURITY_SERVICE_UPDATE_VERSION,
resource_type="share_network",
)
base_security_service_check = ShareNetworkSecurityServiceCheckReadWriteTests
class ShareNetworkSecServiceCheckRWNFSTest(base_security_service_check):
protocol = 'nfs'
class ShareNetworkSecServiceCheckRWTestsCIFSTest(base_security_service_check):
protocol = 'cifs'

View File

@@ -1,122 +0,0 @@
# 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 testtools
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
@testtools.skipUnless(
CONF.run_replication_tests, "Replication tests are disabled."
)
@utils.skip_if_microversion_not_supported('2.47')
class ShareReplicaExportLocationsTest(base.BaseTestCase):
def _create_share_and_replica(self):
replication_type = CONF.replication_type
share_type = self.create_share_type(
driver_handles_share_servers=False,
extra_specs={'replication_type': replication_type},
)
share = self.create_share(
share_type=share_type['ID'], client=self.get_user_client()
)
share_replica = self.create_share_replica(share['id'])
return share, share_replica
@ddt.data('admin', 'user')
def test_list_share_export_locations(self, role):
share, share_replica = self._create_share_and_replica()
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_replica_export_locations(
share_replica['id']
)
self.assertGreater(len(export_locations), 0)
expected_keys = [
'ID',
'Path',
'Preferred',
'Replica State',
'Availability Zone',
]
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['ID']))
self.assertIn(el['Preferred'], ('True', 'False'))
@ddt.data('admin', 'user')
def test_list_share_export_locations_with_columns(self, role):
share, share_replica = self._create_share_and_replica()
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_replica_export_locations(
share_replica['id'], columns='id,path'
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('Id', 'Path')
unexpected_keys = ('Updated At', 'Created At')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
for key in unexpected_keys:
self.assertNotIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['Id']))
@ddt.data('admin', 'user')
def test_get_share_replica_export_location(self, role):
share, share_replica = self._create_share_and_replica()
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_share_replica_export_locations(
share_replica['id']
)
el = client.get_share_replica_export_location(
share_replica['id'], export_locations[0]['ID']
)
expected_keys = [
'path',
'updated_at',
'created_at',
'id',
'preferred',
'replica_state',
'availability_zone',
]
if role == 'admin':
expected_keys.extend(['is_admin_only', 'share_instance_id'])
for key in expected_keys:
self.assertIn(key, el)
if role == 'admin':
self.assertTrue(uuidutils.is_uuid_like(el['share_instance_id']))
self.assertIn(el['is_admin_only'], ('True', 'False'))
self.assertTrue(uuidutils.is_uuid_like(el['id']))
self.assertIn(el['preferred'], ('True', 'False'))
for list_k, get_k in (
('ID', 'id'),
('Path', 'path'),
('Preferred', 'preferred'),
('Replica State', 'replica_state'),
('Availability Zone', 'availability_zone'),
):
self.assertEqual(export_locations[0][list_k], el[get_k])

View File

@@ -1,51 +0,0 @@
# 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 manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@utils.skip_if_microversion_not_supported('2.72')
class ShareReplicasTest(base.BaseTestCase):
def _create_share_and_replica(self):
replication_type = CONF.replication_type
share_type = self.create_share_type(
driver_handles_share_servers=True,
extra_specs={'replication_type': replication_type},
)
share_network = self.create_share_network()
share = self.create_share(
share_type=share_type['ID'],
share_network=share_network['id'],
client=self.get_user_client(),
)
share_replica = self.create_share_replica(
share['id'],
share_network=share_network['id'],
wait_for_creation=True,
client=self.get_user_client(),
)
return share, share_replica
def test_share_replica_create(self):
share, share_replica = self._create_share_and_replica()
self.assertEqual(share['id'], share_replica['share_id'])
def test_share_replica_delete(self):
share, share_replica = self._create_share_and_replica()
self.user_client.delete_share_replica(share_replica['id'])
self.user_client.wait_for_share_replica_deletion(share_replica['id'])

View File

@@ -1,405 +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 ast
import ddt
import testtools
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from manilaclient.common import constants
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
class ShareServersReadOnlyTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.client = self.get_admin_client()
def test_share_server_list(self):
self.client.list_share_servers()
def test_share_server_list_with_host_param(self):
self.client.list_share_servers(filters={'host': 'fake_host'})
def test_share_server_list_with_status_param(self):
self.client.list_share_servers(filters={'status': 'fake_status'})
def test_share_server_list_with_share_network_param(self):
self.client.list_share_servers(filters={'share_network': 'fake_sn'})
def test_share_server_list_with_project_id_param(self):
self.client.list_share_servers(
filters={'project_id': 'fake_project_id'}
)
@ddt.data(
'host',
'status',
'project_id',
'share_network',
'host,status,project_id,share_network',
)
def test_share_server_list_with_specified_columns(self, columns):
self.client.list_share_servers(columns=columns)
def test_share_server_list_by_user(self):
self.assertRaises(
exceptions.CommandFailed, self.user_client.list_share_servers
)
@ddt.ddt
class ShareServersReadWriteBase(base.BaseTestCase):
protocol = None
def setUp(self):
super().setUp()
if not CONF.run_share_servers_tests:
message = "share-server tests are disabled."
raise self.skipException(message)
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled."
raise self.skipException(message)
self.client = self.get_admin_client()
if not self.client.share_network:
message = "Can run only with DHSS=True mode"
raise self.skipException(message)
def _create_share_and_share_network(self):
name = data_utils.rand_name('autotest_share_name')
description = data_utils.rand_name('autotest_share_description')
common_share_network = self.client.get_share_network(
self.client.share_network
)
share_net_info = (
utils.get_default_subnet(
self.user_client, common_share_network['id']
)
if utils.share_network_subnets_are_supported()
else common_share_network
)
neutron_net_id = (
share_net_info['neutron_net_id']
if 'none' not in share_net_info['neutron_net_id'].lower()
else None
)
neutron_subnet_id = (
share_net_info['neutron_subnet_id']
if 'none' not in share_net_info['neutron_subnet_id'].lower()
else None
)
share_network = self.client.create_share_network(
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
)
self.share = self.create_share(
share_protocol=self.protocol,
size=1,
name=name,
description=description,
share_network=share_network['id'],
client=self.client,
wait_for_creation=True,
)
self.share = self.client.get_share(self.share['id'])
return self.share, share_network
def _delete_share_and_share_server(self, share_id, share_server_id):
# Delete share
self.client.delete_share(share_id)
self.client.wait_for_share_deletion(share_id)
# Delete share server
self.client.delete_share_server(share_server_id)
self.client.wait_for_share_server_deletion(share_server_id)
def test_get_and_delete_share_server(self):
self.share, share_network = self._create_share_and_share_network()
share_server_id = self.client.get_share(self.share['id'])[
'share_server_id'
]
# Get share server
server = self.client.get_share_server(share_server_id)
expected_keys = (
'id',
'host',
'status',
'created_at',
'updated_at',
'share_network_id',
'share_network_name',
'project_id',
)
if utils.is_microversion_supported('2.49'):
expected_keys += ('identifier', 'is_auto_deletable')
for key in expected_keys:
self.assertIn(key, server)
self._delete_share_and_share_server(self.share['id'], share_server_id)
self.client.delete_share_network(share_network['id'])
@testtools.skipUnless(
CONF.run_manage_tests, 'Share Manage/Unmanage tests are disabled.'
)
@utils.skip_if_microversion_not_supported('2.49')
def test_manage_and_unmanage_share_server(self):
share, share_network = self._create_share_and_share_network()
share_server_id = self.client.get_share(self.share['id'])[
'share_server_id'
]
server = self.client.get_share_server(share_server_id)
server_host = server['host']
export_location = self.client.list_share_export_locations(
self.share['id']
)[0]['Path']
share_host = share['host']
identifier = server['identifier']
self.assertEqual('True', server['is_auto_deletable'])
# Unmanages share
self.client.unmanage_share(share['id'])
self.client.wait_for_share_deletion(share['id'])
server = self.client.get_share_server(share_server_id)
self.assertEqual('False', server['is_auto_deletable'])
# Unmanages share server
self.client.unmanage_server(share_server_id)
self.client.wait_for_share_server_deletion(share_server_id)
# Manage share server
managed_share_server_id = self.client.share_server_manage(
server_host, share_network['id'], identifier
)
self.client.wait_for_resource_status(
managed_share_server_id,
constants.STATUS_ACTIVE,
resource_type='share_server',
)
managed_server = self.client.get_share_server(managed_share_server_id)
self.assertEqual('False', managed_server['is_auto_deletable'])
# Manage share
managed_share_id = self.client.manage_share(
share_host, self.protocol, export_location, managed_share_server_id
)
self.client.wait_for_resource_status(
managed_share_id, constants.STATUS_AVAILABLE
)
self._delete_share_and_share_server(
managed_share_id, managed_share_server_id
)
self.client.delete_share_network(share_network['id'])
class ShareServersReadWriteNFSTest(ShareServersReadWriteBase):
protocol = 'nfs'
class ShareServersReadWriteCIFSTest(ShareServersReadWriteBase):
protocol = 'cifs'
@ddt.ddt
@utils.skip_if_microversion_not_supported('2.57')
class ShareServersMigrationBase(base.BaseTestCase):
protocol = None
def setUp(self):
super().setUp()
if not CONF.run_share_servers_tests:
message = "Share-server tests are disabled."
raise self.skipException(message)
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled."
raise self.skipException(message)
self.client = self.get_admin_client()
if not self.client.share_network:
message = "Can run only with DHSS=True mode"
raise self.skipException(message)
if not CONF.run_share_servers_migration_tests:
message = "Share server migration tests are disabled."
raise self.skipException(message)
def _create_share_and_share_network(self):
name = data_utils.rand_name('autotest_share_name')
description = data_utils.rand_name('autotest_share_description')
common_share_network = self.client.get_share_network(
self.client.share_network
)
share_net_info = utils.get_default_subnet(
self.client, common_share_network['id']
)
neutron_net_id = (
share_net_info['neutron_net_id']
if 'none' not in share_net_info['neutron_net_id'].lower()
else None
)
neutron_subnet_id = (
share_net_info['neutron_subnet_id']
if 'none' not in share_net_info['neutron_subnet_id'].lower()
else None
)
share_network = self.client.create_share_network(
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
)
share_type = self.create_share_type(
data_utils.rand_name('test_share_type'),
driver_handles_share_servers=True,
)
share = self.create_share(
share_protocol=self.protocol,
size=1,
name=name,
description=description,
share_type=share_type['ID'],
share_network=share_network['id'],
client=self.client,
wait_for_creation=True,
)
share = self.client.get_share(share['id'])
return share, share_network
@ddt.data('cancel', 'complete')
def test_share_server_migration(self, operation):
# Create a share and share network to be used in the tests.
share, share_network = self._create_share_and_share_network()
share_server_id = share['share_server_id']
src_host = share['host'].split('#')[0]
pools = self.admin_client.pool_list(detail=True)
host_list = list()
# Filter the backends DHSS True and different
# than the source host.
for hosts in pools:
host_name = hosts['Name'].split('#')[0]
if (
ast.literal_eval(hosts['Capabilities']).get(
'driver_handles_share_servers'
)
and host_name != src_host
):
host_list.append(host_name)
host_list = list(set(host_list))
# If not found any host we need skip the test.
if len(host_list) == 0:
raise self.skipException(
"No hosts available for share server migration."
)
dest_backend = None
# If found at least one host, we still need to verify the
# share server migration compatibility with the destination host.
for host in host_list:
compatibility = self.admin_client.share_server_migration_check(
server_id=share_server_id,
dest_host=host,
writable=False,
nondisruptive=False,
preserve_snapshots=False,
new_share_network=None,
)
# If found at least one compatible host, we will use it.
if compatibility['compatible']:
dest_host = host
# If not found, we need skip the test.
if dest_backend is not None:
raise self.skipException(
"No hosts compatible to perform a share server migration."
)
# Start the share server migration
self.admin_client.share_server_migration_start(
share_server_id, dest_host
)
server = self.admin_client.get_share_server(share_server_id)
share = self.admin_client.get_share(share['id'])
self.assertEqual(constants.STATUS_SERVER_MIGRATING, share['status'])
# Wait for the share server migration driver phase 1 done.
task_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
server = self.admin_client.wait_for_server_migration_task_state(
share_server_id, dest_host, task_state
)
migration_progress = (
self.admin_client.share_server_migration_get_progress(
share_server_id
)
)
dest_share_server_id = migration_progress.get(
'destination_share_server_id'
)
# Call share server migration complete or cancel operations
# according the ddt.
if operation == 'complete':
task_state = constants.TASK_STATE_MIGRATION_SUCCESS
self.admin_client.share_server_migration_complete(share_server_id)
server = self.admin_client.wait_for_server_migration_task_state(
dest_share_server_id, dest_host, task_state
)
self.admin_client.wait_for_share_server_deletion(share_server_id)
else:
self.admin_client.share_server_migration_cancel(server['id'])
task_state = constants.TASK_STATE_MIGRATION_CANCELLED
# Wait for the respectives task state for each operation above.
server = self.admin_client.wait_for_server_migration_task_state(
server['id'], dest_host, task_state
)
# Check if the share is available again.
share = self.admin_client.get_share(share['id'])
self.assertEqual('available', share['status'])
class ShareServersMigrationNFSTest(ShareServersMigrationBase):
protocol = 'nfs'
class ShareServersMigrationCIFSTest(ShareServersMigrationBase):
protocol = 'cifs'
def load_tests(loader, tests, _):
result = []
for test_case in tests:
if type(test_case._tests[0]) is ShareServersReadWriteBase:
continue
if type(test_case._tests[0]) is ShareServersMigrationBase:
continue
result.append(test_case)
return loader.suiteClass(result)

View File

@@ -1,100 +0,0 @@
# Copyright (c) 2022 China Telecom Digital Intelligence.
# 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 manilaclient.tests.functional import base
class ShareTransferTests(base.BaseTestCase):
"""Check of base share transfers command"""
def setUp(self):
super().setUp()
self.share_type = self.create_share_type(
name=data_utils.rand_name('test_share_type'),
driver_handles_share_servers=False,
)
def test_transfer_create_list_show_delete(self):
"""Create, list, show and delete a share transfer"""
self.skip_if_microversion_not_supported('2.77')
share = self.create_share(
share_protocol='nfs',
size=1,
name=data_utils.rand_name('autotest_share_name'),
client=self.user_client,
share_type=self.share_type['ID'],
use_wait_option=True,
)
self.assertEqual("available", share['status'])
# create share transfer
transfer = self.create_share_transfer(
share['id'], name='test_share_transfer'
)
self.assertIn('auth_key', transfer)
# list share transfers
transfers = self.list_share_transfer()
# We must have at least one transfer
self.assertTrue(len(transfers) > 0)
# show the share transfer
transfer_show = self.get_share_transfer(transfer['id'])
self.assertEqual(transfer_show['name'], transfer['name'])
self.assertNotIn('auth_key', transfer_show)
# delete share transfer
self.delete_share_transfer(transfer['id'])
self.user_client.wait_for_transfer_deletion(transfer['id'])
share = self.user_client.get_share(share['id'])
self.assertEqual("available", share['status'])
# finally delete the share
self.user_client.delete_share(share['id'])
self.user_client.wait_for_share_deletion(share['id'])
def test_transfer_accept(self):
"""Show share transfer accept"""
self.skip_if_microversion_not_supported('2.77')
share = self.create_share(
share_protocol='nfs',
size=1,
name=data_utils.rand_name('autotest_share_name'),
client=self.user_client,
share_type=self.share_type['ID'],
use_wait_option=True,
)
self.assertEqual("available", share['status'])
# create share transfer
transfer = self.create_share_transfer(
share['id'], name='test_share_transfer'
)
share = self.user_client.get_share(share['id'])
transfer_id = transfer['id']
auth_key = transfer['auth_key']
self.assertEqual("share", transfer['resource_type'])
self.assertEqual('test_share_transfer', transfer['name'])
self.assertEqual("awaiting_transfer", share['status'])
# accept the share transfer
self.accept_share_transfer(transfer_id, auth_key)
# after accept complete, the transfer will be deleted.
self.user_client.wait_for_transfer_deletion(transfer_id)
share = self.user_client.get_share(share['id'])
# check share status roll back to available
self.assertEqual("available", share['status'])
# finally delete the share
self.user_client.delete_share(share['id'])
self.user_client.wait_for_share_deletion(share['id'])

View File

@@ -1,627 +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.lib.common.utils import data_utils
from manilaclient import api_versions
from manilaclient.tests.functional import base
from manilaclient.tests.unit.v2 import test_types as unit_test_types
@ddt.ddt
class ShareTypesReadOnlyTest(base.BaseTestCase):
@ddt.data(
("admin", "1.0"),
("admin", "2.0"),
("admin", "2.6"),
("admin", "2.7"),
("user", "1.0"),
("user", "2.0"),
("user", "2.6"),
("user", "2.7"),
)
@ddt.unpack
def test_share_type_list(self, role, microversion):
self.skip_if_microversion_not_supported(microversion)
self.clients[role].manila("type-list", microversion=microversion)
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_extra_specs_list(self, microversion):
self.skip_if_microversion_not_supported(microversion)
self.admin_client.manila("extra-specs-list", microversion=microversion)
@ddt.ddt
class ShareTypesReadWriteTest(base.BaseTestCase):
create_keys = (
'ID',
'Name',
'Visibility',
'is_default',
'required_extra_specs',
'optional_extra_specs',
)
def _share_type_listed_by(
self, share_type_id, by_admin=False, list_all=False, microversion=None
):
client = self.admin_client if by_admin else self.user_client
share_types = client.list_share_types(
list_all=list_all, microversion=microversion
)
return any(share_type_id == st['ID'] for st in share_types)
def _verify_access(self, share_type_id, is_public, microversion=None):
if is_public:
# Verify that it is listed with common 'type-list' operation.
share_types = self.admin_client.list_share_types(
list_all=False, microversion=microversion
)
self.assertTrue(
any(share_type_id == st['ID'] for st in share_types)
)
else:
# Verify that it is not listed for user
self.assertFalse(
self._share_type_listed_by(
share_type_id=share_type_id,
by_admin=False,
list_all=True,
microversion=microversion,
)
)
# Verify it is listed for admin
self.assertTrue(
self._share_type_listed_by(
share_type_id=share_type_id,
by_admin=True,
list_all=True,
microversion=microversion,
)
)
# Verify it is not listed by default
self.assertFalse(
self._share_type_listed_by(
share_type_id=share_type_id,
by_admin=True,
list_all=False,
microversion=microversion,
)
)
@ddt.data(*unit_test_types.get_valid_type_create_data_2_0())
@ddt.unpack
def test_create_delete_share_type(
self, is_public, dhss, spec_snapshot_support, extra_specs
):
self.skip_if_microversion_not_supported('2.0')
self._test_create_delete_share_type(
'2.0',
is_public,
dhss,
spec_snapshot_support,
None,
None,
None,
extra_specs,
)
@ddt.data(*unit_test_types.get_valid_type_create_data_2_24())
@ddt.unpack
def test_create_delete_share_type_2_24(
self,
is_public,
dhss,
spec_snapshot_support,
spec_create_share_from_snapshot,
extra_specs,
):
self.skip_if_microversion_not_supported('2.24')
self._test_create_delete_share_type(
'2.24',
is_public,
dhss,
spec_snapshot_support,
spec_create_share_from_snapshot,
None,
None,
extra_specs,
)
@ddt.data(*unit_test_types.get_valid_type_create_data_2_27())
@ddt.unpack
def test_create_delete_share_type_2_27(
self,
is_public,
dhss,
spec_snapshot_support,
spec_create_share_from_snapshot,
spec_revert_to_snapshot_support,
extra_specs,
):
self.skip_if_microversion_not_supported('2.27')
self._test_create_delete_share_type(
'2.27',
is_public,
dhss,
spec_snapshot_support,
spec_create_share_from_snapshot,
spec_revert_to_snapshot_support,
None,
extra_specs,
)
def test_create_delete_share_type_with_description(self):
self.skip_if_microversion_not_supported('2.41')
self._test_create_delete_share_type(
'2.41',
True,
False,
None,
None,
None,
None,
None,
description=data_utils.rand_name('test_share_type_description'),
)
@ddt.data(
('name_updated_1', 'description_updated', True),
('name_updated_2', 'description_updated', False),
('name_updated_3', None, None),
(None, 'description_updated', None),
(None, None, True),
(None, None, False),
)
@ddt.unpack
def test_create_update_delete_share_type_2_50(
self, new_name, new_description, new_is_public
):
self.skip_if_microversion_not_supported('2.50')
microversion = '2.50'
share_type_name = data_utils.rand_name('share_type_update_test')
# Create share type
share_type = self.create_share_type(
name=share_type_name,
driver_handles_share_servers=False,
snapshot_support=None,
create_share_from_snapshot=None,
revert_to_snapshot=None,
mount_snapshot=None,
is_public=True,
microversion=microversion,
extra_specs={},
description="share_type_description",
)
st_id = share_type['ID']
# Update share type
st_updated = self.update_share_type(
st_id,
name=new_name,
description=new_description,
is_public=new_is_public,
microversion=microversion,
)
# Verify type name
if new_name:
self.assertEqual(new_name, st_updated['Name'])
# Verify type description
if new_description:
self.assertEqual(new_description, st_updated['Description'])
# Verify public
if new_is_public is not None:
self.assertEqual(
'public' if new_is_public else 'private',
st_updated['Visibility'].lower(),
)
# Delete share type
self.admin_client.delete_share_type(st_id, microversion=microversion)
# Wait for share type deletion
self.admin_client.wait_for_share_type_deletion(
st_id, microversion=microversion
)
# Verify that it is not listed with common 'type-list' operation.
share_types = self.admin_client.list_share_types(
list_all=False, microversion=microversion
)
self.assertFalse(any(st_id == st['ID'] for st in share_types))
def test_unset_share_type_description_2_50(self):
self.skip_if_microversion_not_supported('2.50')
microversion = '2.50'
share_type_name = data_utils.rand_name('share_type_update_test')
# Create share type
share_type = self.create_share_type(
name=share_type_name,
driver_handles_share_servers=False,
snapshot_support=None,
create_share_from_snapshot=None,
revert_to_snapshot=None,
mount_snapshot=None,
is_public=True,
microversion=microversion,
extra_specs={},
description="share_type_description",
)
st_id = share_type['ID']
# Update share type
new_description = ""
st_updated = self.update_share_type(
st_id, description=new_description, microversion=microversion
)
# Verify type description
self.assertEqual('None', st_updated['Description'])
# Delete share type
self.admin_client.delete_share_type(st_id, microversion=microversion)
# Wait for share type deletion
self.admin_client.wait_for_share_type_deletion(
st_id, microversion=microversion
)
# Verify that it is not listed with common 'type-list' operation.
share_types = self.admin_client.list_share_types(
list_all=False, microversion=microversion
)
self.assertFalse(any(st_id == st['ID'] for st in share_types))
def _test_create_delete_share_type(
self,
microversion,
is_public,
dhss,
spec_snapshot_support,
spec_create_share_from_snapshot,
spec_revert_to_snapshot_support,
spec_mount_snapshot_support,
extra_specs,
description=None,
):
share_type_name = data_utils.rand_name('manilaclient_functional_test')
if extra_specs is None:
extra_specs = {}
# Create share type
share_type = self.create_share_type(
name=share_type_name,
driver_handles_share_servers=dhss,
snapshot_support=spec_snapshot_support,
create_share_from_snapshot=spec_create_share_from_snapshot,
revert_to_snapshot=spec_revert_to_snapshot_support,
mount_snapshot=spec_mount_snapshot_support,
is_public=is_public,
microversion=microversion,
extra_specs=extra_specs,
description=description,
)
# Verify response body
for key in self.create_keys:
self.assertIn(key, share_type)
# Verify type name
self.assertEqual(share_type_name, share_type['Name'])
# Verify type description
if api_versions.APIVersion(microversion) >= api_versions.APIVersion(
'2.41'
):
self.assertEqual(description, share_type['Description'])
else:
self.assertNotIn('description', share_type)
# Verify required DHSS extra spec
dhss_expected = f'driver_handles_share_servers : {dhss}'
self.assertEqual(dhss_expected, share_type['required_extra_specs'])
# Determine expected extra specs. Note that prior to 2.24,
# the standard 'snapshot_support' extra spec was required.
expected_extra_specs = []
for key, val in extra_specs.items():
expected_extra_specs.append((f'{key} : {val}').strip())
if api_versions.APIVersion(microversion) < api_versions.APIVersion(
'2.24'
):
if 'snapshot_support' not in extra_specs:
if spec_snapshot_support is None:
expected_extra_specs.append(
('{} : {}'.format('snapshot_support', True)).strip()
)
else:
expected_extra_specs.append(
(
'{} : {}'.format(
'snapshot_support', spec_snapshot_support
)
).strip()
)
else:
if spec_snapshot_support is not None:
expected_extra_specs.append(
(
'{} : {}'.format(
'snapshot_support', spec_snapshot_support
)
).strip()
)
if spec_create_share_from_snapshot is not None:
expected_extra_specs.append(
(
'{} : {}'.format(
'create_share_from_snapshot_support',
spec_create_share_from_snapshot,
)
).strip()
)
if spec_revert_to_snapshot_support is not None:
expected_extra_specs.append(
(
'{} : {}'.format(
'revert_to_snapshot_support',
spec_revert_to_snapshot_support,
)
).strip()
)
if spec_mount_snapshot_support is not None:
expected_extra_specs.append(
(
'{} : {}'.format(
'mount_snapshot_support', spec_mount_snapshot_support
)
).strip()
)
# Verify optional extra specs
optional_extra_specs = share_type['optional_extra_specs']
if optional_extra_specs == '':
optional_extra_specs = []
elif not isinstance(optional_extra_specs, list):
optional_extra_specs = [optional_extra_specs]
self.assertEqual(len(expected_extra_specs), len(optional_extra_specs))
for e in optional_extra_specs:
self.assertIn(e.strip(), expected_extra_specs)
# Verify public & default attributes
self.assertEqual(
'public' if is_public else 'private',
share_type['Visibility'].lower(),
)
self.assertEqual('-', share_type['is_default'])
# Verify its access
st_id = share_type['ID']
self._verify_access(
share_type_id=st_id, is_public=is_public, microversion=microversion
)
# Delete share type
self.admin_client.delete_share_type(st_id, microversion=microversion)
# Wait for share type deletion
self.admin_client.wait_for_share_type_deletion(
st_id, microversion=microversion
)
# Verify that it is not listed with common 'type-list' operation.
share_types = self.admin_client.list_share_types(
list_all=False, microversion=microversion
)
self.assertFalse(any(st_id == st['ID'] for st in share_types))
@ddt.data("2.6", "2.7")
def test_add_remove_access_to_private_share_type(self, microversion):
self.skip_if_microversion_not_supported(microversion)
share_type_name = data_utils.rand_name('manilaclient_functional_test')
is_public = False
# Create share type
share_type = self.create_share_type(
name=share_type_name,
driver_handles_share_servers='False',
is_public=is_public,
microversion=microversion,
)
st_id = share_type['ID']
user_project_id = self.admin_client.get_project_id(
self.user_client.tenant_name
)
self._verify_access(
share_type_id=st_id,
is_public=is_public,
microversion=microversion,
)
# Project ID is in access list - false
st_access_list = self.admin_client.list_share_type_access(
st_id, microversion=microversion
)
self.assertNotIn(user_project_id, st_access_list)
# Add access for project of user
self.admin_client.add_share_type_access(
st_id, user_project_id, microversion=microversion
)
# Verify it is listed for user as well as for admin
self.assertTrue(
self._share_type_listed_by(
share_type_id=st_id, by_admin=False, list_all=True
)
)
self.assertTrue(
self._share_type_listed_by(
share_type_id=st_id, by_admin=True, list_all=True
)
)
# Project ID is in access list - true
st_access_list = self.admin_client.list_share_type_access(
st_id, microversion=microversion
)
self.assertIn(user_project_id, st_access_list)
# Remove access
self.admin_client.remove_share_type_access(
st_id, user_project_id, microversion=microversion
)
self._verify_access(
share_type_id=st_id,
is_public=is_public,
microversion=microversion,
)
# Project ID is in access list - false
st_access_list = self.admin_client.list_share_type_access(
st_id, microversion=microversion
)
self.assertNotIn(user_project_id, st_access_list)
@ddt.data("2.6", "2.7")
def test_list_share_type(self, microversion):
share_type_name = data_utils.rand_name('manilaclient_functional_test')
# Create share type
self.create_share_type(
name=share_type_name, driver_handles_share_servers='False'
)
share_types = self.admin_client.list_share_types(
list_all=True, microversion=microversion
)
self.assertTrue(any(s['ID'] is not None for s in share_types))
self.assertTrue(any(s['Name'] is not None for s in share_types))
self.assertTrue(any(s['visibility'] is not None for s in share_types))
@ddt.data("2.6", "2.7")
def test_list_share_type_select_column(self, microversion):
share_type_name = data_utils.rand_name('manilaclient_functional_test')
# Create share type
self.create_share_type(
name=share_type_name, driver_handles_share_servers='False'
)
share_types = self.admin_client.list_share_types(
list_all=True, columns="id,name", microversion=microversion
)
self.assertTrue(any(s['id'] is not None for s in share_types))
self.assertTrue(any(s['name'] is not None for s in share_types))
self.assertTrue(all('visibility' not in s for s in share_types))
self.assertTrue(all('Visibility' not in s for s in share_types))
def test_list_share_type_filter_search(self):
# Fake extra spec and type name
extra_specs = {'aaaa': 'bbbb'}
# Create share type
name1 = data_utils.rand_name('manilaclient_functional_test1')
self.create_share_type(
name=name1, driver_handles_share_servers='False'
)
# Create share type
name2 = data_utils.rand_name('manilaclient_functional_test2')
self.create_share_type(
name=name2,
extra_specs=extra_specs,
driver_handles_share_servers='True',
)
# List type by extra_specs
list_all = False
search_opts = {'extra_specs': extra_specs}
share_types = self.admin_client.list_share_types(
list_all=list_all, search_opts=search_opts, microversion='2.43'
)
self.assertTrue(share_types is not None)
expect = 'aaaa : bbbb'
self.assertTrue(len(share_types) == 1)
self.assertTrue(all('optional_extra_specs' in s for s in share_types))
self.assertTrue(all(s['Name'] == name2 for s in share_types))
self.assertTrue(
all(s['optional_extra_specs'] == expect for s in share_types)
)
@ddt.ddt
class ShareTypeExtraSpecsReadWriteTest(base.BaseTestCase):
@ddt.data(
(True, False),
(True, True),
(False, True),
(False, False),
(False, False, "2.6"),
(False, False, "2.7"),
)
@ddt.unpack
def test_share_type_extra_specs_life_cycle(
self, is_public, dhss, microversion=None
):
if microversion:
self.skip_if_microversion_not_supported(microversion)
# Create share type
st = self.create_share_type(
driver_handles_share_servers=dhss,
is_public=is_public,
microversion=microversion,
)
# Add extra specs to share type
st_extra_specs = dict(foo_key='foo_value', bar_key='bar_value')
self.admin_client.set_share_type_extra_specs(
st['ID'], st_extra_specs, microversion=microversion
)
# View list of extra specs
extra_specs = self.admin_client.list_share_type_extra_specs(
st['ID'], microversion=microversion
)
for k, v in st_extra_specs.items():
self.assertIn(f'{k} : {v}', extra_specs)
# Remove one extra spec
self.admin_client.unset_share_type_extra_specs(
st['ID'], ('foo_key',), microversion=microversion
)
# Verify that removed extra spec is absent
extra_specs = self.admin_client.list_share_type_extra_specs(
st['ID'], microversion=microversion
)
self.assertNotIn('foo_key : foo_value', extra_specs)
self.assertIn('bar_key : bar_value', extra_specs)
self.assertIn(f'driver_handles_share_servers : {dhss}', extra_specs)

View File

@@ -1,339 +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
import testtools
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from manilaclient.common import constants
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
class SharesReadWriteBase(base.BaseTestCase):
protocol = None
def setUp(self):
super().setUp()
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled"
raise self.skipException(message)
self.name = data_utils.rand_name('autotest_share_name')
self.description = data_utils.rand_name('autotest_share_description')
# NOTE(vponomaryov): following share is used only in one test
# until tests for snapshots appear.
self.share = self.create_share(
share_protocol=self.protocol,
size=1,
name=self.name,
description=self.description,
client=self.get_user_client(),
)
def test_create_delete_share(self):
name = data_utils.rand_name('autotest_share_name')
create = self.create_share(
self.protocol, name=name, client=self.user_client
)
self.assertEqual("creating", create['status'])
self.assertEqual(name, create['name'])
self.assertEqual('1', create['size'])
self.assertEqual(self.protocol.upper(), create['share_proto'])
self.user_client.delete_share(create['id'])
self.user_client.wait_for_share_deletion(create['id'])
def test_create_update_share(self):
name = data_utils.rand_name('autotest_share_name')
new_name = 'new_' + name
description = data_utils.rand_name('autotest_share_description')
new_description = 'new_' + description
create = self.create_share(
self.protocol,
name=name,
description=description,
client=self.user_client,
)
self.assertEqual(name, create['name'])
self.assertEqual(description, create['description'])
self.assertEqual('False', create['is_public'])
self.user_client.update_share(
create['id'], name=new_name, description=new_description
)
get = self.user_client.get_share(create['id'])
self.assertEqual(new_name, get['name'])
self.assertEqual(new_description, get['description'])
self.assertEqual('False', get['is_public'])
# only admins operating at system scope can set a share to be public
self.admin_client.update_share(create['id'], is_public=True)
get = self.user_client.get_share(create['id'])
self.assertEqual(new_name, get['name'])
self.assertEqual(new_description, get['description'])
self.assertEqual('True', get['is_public'])
def test_get_share(self):
get = self.user_client.get_share(self.share['id'])
self.assertEqual(self.name, get['name'])
self.assertEqual(self.description, get['description'])
self.assertEqual('1', get['size'])
self.assertEqual(self.protocol.upper(), get['share_proto'])
def test_create_delete_with_wait(self):
name = data_utils.rand_name('share-with-wait-%s')
description = data_utils.rand_name('we-wait-until-share-is-ready')
share_1, share_2 = (
self.create_share(
self.protocol,
name=(name % num),
description=description,
use_wait_option=True,
client=self.user_client,
)
for num in range(0, 2)
)
self.assertEqual("available", share_1['status'])
self.assertEqual("available", share_2['status'])
self.delete_share(
[share_1['id'], share_2['id']], wait=True, client=self.user_client
)
for share in (share_1, share_2):
self.assertRaises(
exceptions.NotFound, self.user_client.get_share, share['id']
)
def test_create_soft_delete_and_restore_share(self):
self.skip_if_microversion_not_supported('2.69')
microversion = '2.69'
description = data_utils.rand_name('we-wait-until-share-is-ready')
share = self.create_share(
self.protocol,
name='share_name',
description=description,
use_wait_option=True,
client=self.user_client,
)
self.assertEqual("available", share['status'])
# soft delete the share to recycle bin
self.soft_delete_share(
[share['id']], client=self.user_client, microversion=microversion
)
self.user_client.wait_for_share_soft_deletion(share['id'])
# get shares list in recycle bin
result = self.user_client.list_shares(
is_soft_deleted=True, microversion=microversion
)
share_ids = [sh['ID'] for sh in result]
# check share is in recycle bin
self.assertIn(share['id'], share_ids)
# restore the share from recycle bin
self.restore_share(
[share['id']], client=self.user_client, microversion=microversion
)
self.user_client.wait_for_share_restore(share['id'])
result1 = self.user_client.list_shares(
is_soft_deleted=True, microversion=microversion
)
share_ids1 = [sh['ID'] for sh in result1]
# check share not in recycle bin
self.assertNotIn(share['id'], share_ids1)
@ddt.ddt
class SharesTestMigration(base.BaseTestCase):
def setUp(self):
super().setUp()
self.old_type = self.create_share_type(
data_utils.rand_name('test_share_type'),
driver_handles_share_servers=True,
)
self.new_type = self.create_share_type(
data_utils.rand_name('test_share_type'),
driver_handles_share_servers=True,
)
self.error_type = self.create_share_type(
data_utils.rand_name('test_share_type'),
driver_handles_share_servers=True,
extra_specs={'cause_error': 'no_valid_host'},
)
self.old_share_net = self.get_user_client().get_share_network(
self.get_user_client().share_network
)
share_net_info = (
utils.get_default_subnet(
self.get_user_client(), self.old_share_net['id']
)
if utils.share_network_subnets_are_supported()
else self.old_share_net
)
self.new_share_net = self.create_share_network(
neutron_net_id=share_net_info['neutron_net_id'],
neutron_subnet_id=share_net_info['neutron_subnet_id'],
)
@utils.skip_if_microversion_not_supported('2.22')
@ddt.data('migration_error', 'migration_success', 'None')
def test_reset_task_state(self, state):
share = self.create_share(
share_protocol='nfs',
size=1,
name=data_utils.rand_name('autotest_share_name'),
client=self.get_user_client(),
share_type=self.old_type['ID'],
share_network=self.old_share_net['id'],
wait_for_creation=True,
)
share = self.user_client.get_share(share['id'])
self.admin_client.reset_task_state(share['id'], state)
share = self.user_client.get_share(share['id'])
self.assertEqual(state, share['task_state'])
@utils.skip_if_microversion_not_supported('2.29')
@testtools.skipUnless(
CONF.run_migration_tests, 'Share migration tests are disabled.'
)
@ddt.data('cancel', 'success', 'error')
def test_full_migration(self, test_type):
# We are testing with DHSS=True only because it allows us to specify
# new_share_network.
share = self.create_share(
share_protocol='nfs',
size=1,
name=data_utils.rand_name('autotest_share_name'),
client=self.get_user_client(),
share_type=self.old_type['ID'],
share_network=self.old_share_net['id'],
wait_for_creation=True,
)
share = self.admin_client.get_share(share['id'])
pools = self.admin_client.pool_list(detail=True)
dest_pool = utils.choose_matching_backend(share, pools, self.new_type)
self.assertIsNotNone(dest_pool)
source_pool = share['host']
new_type = self.new_type
if test_type == 'error':
statuses = constants.TASK_STATE_MIGRATION_ERROR
new_type = self.error_type
else:
statuses = (
constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
constants.TASK_STATE_DATA_COPYING_COMPLETED,
)
self.admin_client.migration_start(
share['id'],
dest_pool,
writable=True,
nondisruptive=False,
preserve_metadata=True,
preserve_snapshots=True,
force_host_assisted_migration=False,
new_share_network=self.new_share_net['id'],
new_share_type=new_type['ID'],
)
share = self.admin_client.wait_for_migration_task_state(
share['id'], dest_pool, statuses
)
progress = self.admin_client.migration_get_progress(share['id'])
self.assertEqual('100', progress['total_progress'])
self.assertEqual(source_pool, share['host'])
self.assertEqual(self.old_type['ID'], share['share_type'])
self.assertEqual(self.old_share_net['id'], share['share_network_id'])
if test_type == 'error':
self.assertEqual(statuses, progress['task_state'])
else:
if test_type == 'success':
self.admin_client.migration_complete(share['id'])
statuses = constants.TASK_STATE_MIGRATION_SUCCESS
elif test_type == 'cancel':
self.admin_client.migration_cancel(share['id'])
statuses = constants.TASK_STATE_MIGRATION_CANCELLED
share = self.admin_client.wait_for_migration_task_state(
share['id'], dest_pool, statuses
)
progress = self.admin_client.migration_get_progress(share['id'])
self.assertEqual(statuses, progress['task_state'])
if test_type == 'success':
self.assertEqual(dest_pool, share['host'])
self.assertEqual(new_type['ID'], share['share_type'])
self.assertEqual(
self.new_share_net['id'], share['share_network_id']
)
else:
self.assertEqual(source_pool, share['host'])
self.assertEqual(self.old_type['ID'], share['share_type'])
self.assertEqual(
self.old_share_net['id'], share['share_network_id']
)
class NFSSharesReadWriteTest(SharesReadWriteBase):
protocol = 'nfs'
class CIFSSharesReadWriteTest(SharesReadWriteBase):
protocol = 'cifs'
class GlusterFSSharesReadWriteTest(SharesReadWriteBase):
protocol = 'glusterfs'
class HDFSSharesReadWriteTest(SharesReadWriteBase):
protocol = 'hdfs'
class MAPRFSSharesReadWriteTest(SharesReadWriteBase):
protocol = 'maprfs'

View File

@@ -1,414 +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.lib.common.utils import data_utils
from tempest.lib import exceptions
import testtools
from manilaclient.common import constants
from manilaclient import config
from manilaclient.tests.functional import base
CONF = config.CONF
@ddt.ddt
class SharesListReadOnlyTest(base.BaseTestCase):
@ddt.data('admin', 'user')
def test_shares_list(self, role):
self.clients[role].manila('list')
@ddt.data('admin', 'user')
def test_list_with_debug_flag(self, role):
self.clients[role].manila('list', flags='--debug')
@ddt.data('admin', 'user')
def test_shares_list_all_tenants(self, role):
self.clients[role].manila('list', params='--all-tenants')
@ddt.data('admin', 'user')
def test_shares_list_filter_by_name(self, role):
self.clients[role].manila('list', params='--name name')
@ddt.data('admin', 'user')
def test_shares_list_filter_by_export_location(self, role):
self.clients[role].manila('list', params='--export_location fake')
@ddt.data('admin', 'user')
def test_shares_list_filter_by_inexact_name(self, role):
self.clients[role].manila('list', params='--name~ na')
@ddt.data('admin', 'user')
def test_shares_list_filter_by_inexact_description(self, role):
self.clients[role].manila('list', params='--description~ des')
@ddt.data('admin', 'user')
def test_shares_list_filter_by_status(self, role):
self.clients[role].manila('list', params='--status status')
def test_shares_list_filter_by_share_server_as_admin(self):
self.clients['admin'].manila('list', params='--share-server fake')
def test_shares_list_filter_by_share_server_as_user(self):
self.assertRaises(
exceptions.CommandFailed,
self.clients['user'].manila,
'list',
params='--share-server fake',
)
@ddt.data('admin', 'user')
def test_shares_list_filter_by_project_id(self, role):
self.clients[role].manila('list', params='--project-id fake')
def test_shares_list_filter_by_host(self):
self.clients['admin'].manila('list', params='--host fake')
@ddt.data('admin', 'user')
def test_shares_list_with_limit_and_offset(self, role):
self.clients[role].manila('list', params='--limit 1 --offset 1')
@ddt.data(
{'role': 'admin', 'direction': 'asc'},
{'role': 'admin', 'direction': 'desc'},
{'role': 'user', 'direction': 'asc'},
{'role': 'user', 'direction': 'desc'},
)
@ddt.unpack
def test_shares_list_with_sorting(self, role, direction):
self.clients[role].manila(
'list', params='--sort-key host --sort-dir ' + direction
)
@ddt.data('admin', 'user')
def test_snapshot_list(self, role):
self.clients[role].manila('snapshot-list')
@ddt.data('admin', 'user')
def test_snapshot_list_all_tenants(self, role):
self.clients[role].manila('snapshot-list', params='--all-tenants')
@ddt.data('admin', 'user')
def test_snapshot_list_filter_by_name(self, role):
self.clients[role].manila('snapshot-list', params='--name name')
@ddt.data('admin', 'user')
def test_snapshot_list_filter_by_status(self, role):
self.clients[role].manila('snapshot-list', params='--status status')
@ddt.ddt
class SharesListReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.private_name = data_utils.rand_name('autotest_share_name')
self.private_description = data_utils.rand_name(
'autotest_share_description'
)
self.public_name = data_utils.rand_name('autotest_public_share_name')
self.public_description = data_utils.rand_name(
'autotest_public_share_description'
)
self.admin_private_name = data_utils.rand_name(
'autotest_admin_private_share_name'
)
self.admin_private_description = data_utils.rand_name(
'autotest_admin_private_share_description'
)
self.soft_name = data_utils.rand_name('soft_delete_share_name')
self.admin_private_share = self.create_share(
name=self.admin_private_name,
description=self.admin_private_description,
public=False,
client=None,
wait_for_creation=False,
)
self.private_share = self.create_share(
name=self.private_name,
description=self.private_description,
public=False,
client=self.get_user_client(),
wait_for_creation=False,
)
self.public_share = self.create_share(
name=self.public_name,
description=self.public_description,
public=True,
client=self.admin_client,
)
self.wait_soft_delete_share = self.create_share(
name=self.soft_name,
public=False,
client=self.get_user_client(),
wait_for_creation=False,
)
self.shares_created = (
self.private_share['id'],
self.public_share['id'],
self.admin_private_share['id'],
self.wait_soft_delete_share['id'],
)
for share_id in self.shares_created:
self.admin_client.wait_for_resource_status(
share_id, constants.STATUS_AVAILABLE
)
self.soft_delete_share(
[self.wait_soft_delete_share['id']],
client=self.get_user_client(),
microversion='2.69',
)
def _list_shares(self, filters=None):
filters = filters or dict()
shares = self.user_client.list_shares(filters=filters)
self.assertGreater(len(shares), 0)
if filters:
for share in shares:
try:
share_get = self.user_client.get_share(share['ID'])
except exceptions.NotFound:
# NOTE(vponomaryov): Case when some share was deleted
# between our 'list' and 'get' requests. Skip such case.
# It occurs with concurrently running tests.
continue
if 'migrating' in share_get['status']:
# all bets are off, a fair chance share migration
# started between the 'list' and 'get' requests. No need
# to verify these shares.
continue
for filter_key, expected_value in filters.items():
if filter_key in ('share_network', 'share-network'):
filter_key = 'share_network_id'
if share_get[filter_key] != expected_value:
# Possibly a mismatch because the share was
# migrated to a new network in the time that
# elapsed between the 'list' and 'get' requests.
# If this isn't one of the shares created in
# this class, don't worry about such mismatches
self.assertNotIn(
share_get['id'], self.shares_created
)
continue
if (
expected_value != 'deleting'
and share_get[filter_key] == 'deleting'
):
continue
self.assertEqual(expected_value, share_get[filter_key])
def test_list_shares(self):
self._list_shares()
@ddt.data(1, 0)
def test_list_shares_for_all_tenants(self, all_tenants):
shares = self.admin_client.list_shares(all_tenants=all_tenants)
self.assertLessEqual(1, len(shares))
if all_tenants:
self.assertTrue(all('Project ID' in s for s in shares))
for s_id in (
self.private_share['id'],
self.public_share['id'],
self.admin_private_share['id'],
):
self.assertTrue(any(s_id == s['ID'] for s in shares))
else:
self.assertTrue(all('Project ID' not in s for s in shares))
self.assertTrue(
any(self.admin_private_share['id'] == s['ID'] for s in shares)
)
if (
self.private_share['project_id']
!= (self.admin_private_share['project_id'])
):
for s_id in (
self.private_share['id'],
self.public_share['id'],
):
self.assertFalse(any(s_id == s['ID'] for s in shares))
@ddt.data(True, False)
def test_list_shares_with_public(self, public):
shares = self.user_client.list_shares(is_public=public)
self.assertGreater(len(shares), 1)
if public:
self.assertTrue(all('Project ID' in s for s in shares))
else:
self.assertTrue(all('Project ID' not in s for s in shares))
def test_list_shares_by_name(self):
shares = self.user_client.list_shares(
filters={'name': self.private_name}
)
self.assertEqual(1, len(shares))
self.assertTrue(
any(self.private_share['id'] == s['ID'] for s in shares)
)
for share in shares:
get = self.user_client.get_share(share['ID'])
self.assertEqual(self.private_name, get['name'])
def test_list_shares_by_share_type(self):
share_type_id = self.user_client.get_share_type(
self.private_share['share_type']
)['ID']
# NOTE(vponomaryov): this is API 2.6+ specific
self._list_shares({'share_type': share_type_id})
def test_list_shares_by_status(self):
self._list_shares({'status': 'available'})
def test_list_shares_by_project_id(self):
project_id = self.user_client.get_project_id(
self.user_client.tenant_name
)
self._list_shares({'project_id': project_id})
@testtools.skipUnless(
CONF.share_network, "Usage of Share networks is disabled"
)
def test_list_shares_by_share_network(self):
share_network_id = self.user_client.get_share_network(
CONF.share_network
)['id']
self._list_shares({'share_network': share_network_id})
@ddt.data(
{'limit': 1},
{'limit': 2},
{'limit': 1, 'offset': 1},
{'limit': 2, 'offset': 0},
)
def test_list_shares_with_limit(self, filters):
shares = self.user_client.list_shares(filters=filters)
self.assertEqual(filters['limit'], len(shares))
def test_list_share_select_column(self):
shares = self.user_client.list_shares(columns="Name,Size")
self.assertTrue(any(s['Name'] is not None for s in shares))
self.assertTrue(any(s['Size'] is not None for s in shares))
self.assertTrue(all('Description' not in s for s in shares))
@ddt.data('ID', 'Path')
def test_list_shares_by_export_location(self, option):
export_locations = self.admin_client.list_share_export_locations(
self.public_share['id']
)
shares = self.admin_client.list_shares(
filters={'export_location': export_locations[0][option]}
)
self.assertEqual(1, len(shares))
self.assertTrue(
any(self.public_share['id'] == s['ID'] for s in shares)
)
for share in shares:
get = self.admin_client.get_share(share['ID'])
self.assertEqual(self.public_name, get['name'])
@ddt.data('ID', 'Path')
def test_list_share_instances_by_export_location(self, option):
export_locations = self.admin_client.list_share_export_locations(
self.public_share['id']
)
share_instances = self.admin_client.list_share_instances(
filters={'export_location': export_locations[0][option]}
)
self.assertEqual(1, len(share_instances))
share_instance_id = share_instances[0]['ID']
except_export_locations = (
self.admin_client.list_share_instance_export_locations(
share_instance_id
)
)
self.assertGreater(len(except_export_locations), 0)
self.assertTrue(
any(
export_locations[0][option] == e[option]
for e in except_export_locations
)
)
def test_list_share_by_export_location_with_invalid_version(self):
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.list_shares,
filters={'export_location': 'fake'},
microversion='2.34',
)
def test_list_share_instance_by_export_location_invalid_version(self):
self.assertRaises(
exceptions.CommandFailed,
self.admin_client.list_share_instances,
filters={'export_location': 'fake'},
microversion='2.34',
)
@ddt.data('name', 'description')
def test_list_shares_by_inexact_option(self, option):
shares = self.user_client.list_shares(filters={option + '~': option})
# We know we have to have atleast three shares.
# Due to test concurrency, there can be
# more than three shares (some created by other tests).
self.assertGreaterEqual(len(shares), 3)
self.assertTrue(
any(self.private_share['id'] == s['ID'] for s in shares)
)
def test_list_shares_by_inexact_unicode_option(self):
self.create_share(
name='共享名称', description='共享描述', client=self.user_client
)
filters = {'name~': '名称'}
shares = self.user_client.list_shares(filters=filters)
self.assertGreater(len(shares), 0)
filters = {'description~': '描述'}
shares = self.user_client.list_shares(filters=filters)
self.assertGreater(len(shares), 0)
def test_list_shares_by_description(self):
shares = self.user_client.list_shares(
filters={'description': self.private_description}
)
self.assertEqual(1, len(shares))
self.assertTrue(
any(self.private_share['id'] == s['ID'] for s in shares)
)
def test_list_shares_in_recycle_bin(self):
shares = self.user_client.list_shares(is_soft_deleted=True)
self.assertTrue(
any(self.wait_soft_delete_share['id'] == s['ID'] for s in shares)
)

View File

@@ -1,155 +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 manilaclient.tests.functional import base
@ddt.ddt
class SharesMetadataReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.share = self.create_share(client=self.get_user_client())
def test_set_metadata_in_share_creation(self):
md = {"key1": "value1", "key2": "value2"}
# Create share with metadata
share = self.create_share(metadata=md, client=self.get_user_client())
# Read share metadata
metadata = self.user_client.get_share_metadata(share["id"])
# Verify share metadata
self.assertEqual(2, len(metadata))
self.assertIn('key1', metadata)
self.assertIn('key2', metadata)
self.assertEqual(md['key1'], metadata['key1'])
self.assertEqual(md['key2'], metadata['key2'])
def test_set_and_get_metadata(self):
# Create share
share = self.create_share(
cleanup_in_class=False, client=self.get_user_client()
)
# Set share metadata
md = {"key3": "value3", "key4": "value4"}
self.user_client.set_share_metadata(share["id"], md)
# Read share metadata
metadata = self.user_client.get_share_metadata(share["id"])
# Verify share metadata
self.assertEqual(2, len(metadata))
self.assertIn('key3', metadata)
self.assertIn('key4', metadata)
self.assertEqual(md['key3'], metadata['key3'])
self.assertEqual(md['key4'], metadata['key4'])
def test_set_and_delete_metadata(self):
# Create share
share = self.create_share(
cleanup_in_class=False, client=self.get_user_client()
)
# Set share metadata
md = {"key3": "value3", "key4": "value4"}
self.user_client.set_share_metadata(share["id"], md)
# Unset share metadata
self.user_client.unset_share_metadata(share["id"], list(md.keys()))
# Verify deletion of share metadata
metadata = self.user_client.get_share_metadata(share["id"])
self.assertEqual({}, metadata)
def test_set_and_add_metadata(self):
md = {'key5': 'value5'}
# Create share with metadata
share = self.create_share(
metadata=md, cleanup_in_class=False, client=self.get_user_client()
)
# Set share metadata
self.user_client.set_share_metadata(share["id"], {'key6': 'value6'})
self.user_client.set_share_metadata(share["id"], {'key7': 'value7'})
# Read share metadata
metadata = self.user_client.get_share_metadata(share["id"])
# Verify share metadata
self.assertEqual(3, len(metadata))
for i in (5, 6, 7):
key = f'key{i}'
self.assertIn(key, metadata)
self.assertEqual(f'value{i}', metadata[key])
def test_set_and_replace_metadata(self):
md = {'key8': 'value8'}
# Create share with metadata
share = self.create_share(
metadata=md, cleanup_in_class=False, client=self.get_user_client()
)
# Set share metadata
self.user_client.set_share_metadata(share["id"], {'key9': 'value9'})
# Replace all existing share metadata
self.user_client.update_all_share_metadata(
share["id"], {'key10': 'value10'}
)
# Read share metadata
metadata = self.user_client.get_share_metadata(share["id"])
# Verify share metadata
self.assertEqual(1, len(metadata))
self.assertIn('key10', metadata)
self.assertEqual('value10', metadata['key10'])
@ddt.data(
{"k": "value"}, {"k" * 255: "value"}, {"key": "v"}, {"key": "v" * 1023}
)
def test_set_metadata_min_max_sizes_of_keys_and_values(self, metadata):
# Set share metadata
self.user_client.set_share_metadata(self.share["id"], metadata)
# Read share metadata
get = self.user_client.get_share_metadata(self.share["id"])
# Verify share metadata
key = list(metadata.keys())[0]
self.assertIn(key, get)
self.assertEqual(metadata[key], get[key])
@ddt.data(
{"k": "value"}, {"k" * 255: "value"}, {"key": "v"}, {"key": "v" * 1023}
)
def test_update_metadata_min_max_sizes_of_keys_and_values(self, metadata):
# Update share metadata
self.user_client.update_all_share_metadata(self.share["id"], metadata)
# Read share metadata
get = self.user_client.get_share_metadata(self.share["id"])
# Verify share metadata
self.assertEqual(len(metadata), len(get))
for key in metadata:
self.assertIn(key, get)
self.assertEqual(metadata[key], get[key])

View File

@@ -1,221 +0,0 @@
# Copyright (c) 2017 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.
from tempest.lib import exceptions as tempest_lib_exc
import testtools
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@utils.skip_if_microversion_not_supported('2.32')
class SnapshotAccessReadBase(base.BaseTestCase):
protocol = None
def setUp(self):
super().setUp()
if self.protocol not in CONF.enable_protocols:
message = f"{self.protocol} tests are disabled."
raise self.skipException(message)
self.access_types = CONF.access_types_mapping.get(
self.protocol, ''
).split(' ')
if not self.access_types:
raise self.skipException(
f"No access types were provided for {self.protocol} "
"snapshot access tests."
)
self.share = self.create_share(
share_protocol=self.protocol, client=self.get_user_client()
)
int_range = range(0, 10)
self.access_to = {
'ip': [f'99.88.77.{i}' for i in int_range],
'user': [f'foo_user_{i}' for i in int_range],
'cert': [f'tenant_{i}.example.com' for i in int_range],
}
def _test_create_list_access_rule_for_snapshot(self, snapshot_id):
access = []
access_type = self.access_types[0]
for i in range(5):
access_ = self.user_client.snapshot_access_allow(
snapshot_id, access_type, self.access_to[access_type][i]
)
access.append(access_)
return access
def test_create_list_access_rule_for_snapshot(self):
snapshot = self.create_snapshot(
share=self.share['id'],
client=self.get_user_client(),
cleanup_in_class=False,
)
access = self._test_create_list_access_rule_for_snapshot(
snapshot['id']
)
access_list = self.user_client.list_access(
snapshot['id'], is_snapshot=True
)
for i in range(5):
self.assertIn(
access[i]['id'], [access_list[j]['id'] for j in range(5)]
)
self.assertIn(
access[i]['access_type'],
[access_list[j]['access_type'] for j in range(5)],
)
self.assertIn(
access[i]['access_to'],
[access_list[j]['access_to'] for j in range(5)],
)
self.assertIsNotNone(access_list[i]['access_type'])
self.assertIsNotNone(access_list[i]['access_to'])
def test_create_list_access_rule_for_snapshot_select_column(self):
snapshot = self.create_snapshot(
share=self.share['id'],
client=self.get_user_client(),
cleanup_in_class=False,
)
self._test_create_list_access_rule_for_snapshot(snapshot['id'])
access_list = self.user_client.list_access(
snapshot['id'], columns="access_type,access_to", is_snapshot=True
)
self.assertTrue(any(x['Access_Type'] is not None for x in access_list))
self.assertTrue(any(x['Access_To'] is not None for x in access_list))
def _create_delete_access_rule(self, snapshot_id, access_type, access_to):
if access_type not in self.access_types:
raise self.skipException(
f"'{access_type}' access rules is disabled for protocol "
f"'{self.protocol}'."
)
access = self.user_client.snapshot_access_allow(
snapshot_id, access_type, access_to
)
self.assertEqual(access_type, access.get('access_type'))
self.assertEqual(
access_to.replace('\\\\', '\\'), access.get('access_to')
)
self.user_client.wait_for_access_rule_status(
snapshot_id, access['id'], is_snapshot=True
)
self.user_client.snapshot_access_deny(snapshot_id, access['id'])
self.user_client.wait_for_access_rule_deletion(
snapshot_id, access['id'], is_snapshot=True
)
self.assertRaises(
tempest_lib_exc.NotFound,
self.user_client.get_access,
snapshot_id,
access['id'],
is_snapshot=True,
)
def test_create_delete_snapshot_ip_access_rule(self):
snapshot = self.create_snapshot(
share=self.share['id'],
client=self.get_user_client(),
cleanup_in_class=False,
)
self._create_delete_access_rule(
snapshot['id'], 'ip', self.access_to['ip'][0]
)
def test_create_delete_snapshot_user_access_rule(self):
snapshot = self.create_snapshot(
share=self.share['id'],
client=self.get_user_client(),
cleanup_in_class=False,
)
self._create_delete_access_rule(
snapshot['id'], 'user', CONF.username_for_user_rules
)
def test_create_delete_snapshot_cert_access_rule(self):
snapshot = self.create_snapshot(
share=self.share['id'],
client=self.get_user_client(),
cleanup_in_class=False,
)
self._create_delete_access_rule(
snapshot['id'], 'cert', self.access_to['cert'][0]
)
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
class NFSSnapshotAccessTest(SnapshotAccessReadBase):
protocol = 'nfs'
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
class CIFSSnapshotAccessTest(SnapshotAccessReadBase):
protocol = 'cifs'
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
class GlusterFSSnapshotAccessTest(SnapshotAccessReadBase):
protocol = 'glusterfs'
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
class HDFSSnapshotAccessTest(SnapshotAccessReadBase):
protocol = 'hdfs'
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
class MAPRFSSnapshotAccessTest(SnapshotAccessReadBase):
protocol = 'maprfs'
def load_tests(loader, tests, _):
result = []
for test_case in tests:
if type(test_case._tests[0]) is SnapshotAccessReadBase:
continue
result.append(test_case)
return loader.suiteClass(result)

View File

@@ -1,140 +0,0 @@
# Copyright 2016 Huawei 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 testtools
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
@testtools.skipUnless(CONF.run_snapshot_tests, 'Snapshot tests disabled.')
@utils.skip_if_microversion_not_supported('2.19')
class SnapshotInstancesTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.share = self.create_share(client=self.get_user_client())
self.snapshot = self.create_snapshot(
share=self.share['id'], client=self.get_user_client()
)
def test_list_all_snapshot_instances(self):
snapshot_instances = self.admin_client.list_snapshot_instances()
self.assertGreater(len(snapshot_instances), 0)
expected_keys = ('ID', 'Snapshot ID', 'Status')
for si in snapshot_instances:
for key in expected_keys:
self.assertIn(key, si)
self.assertTrue(uuidutils.is_uuid_like(si['ID']))
self.assertTrue(uuidutils.is_uuid_like(si['Snapshot ID']))
def test_list_all_snapshot_instances_details(self):
snapshot_instances = self.admin_client.list_snapshot_instances(
detailed=True
)
self.assertGreater(len(snapshot_instances), 0)
expected_keys = (
'ID',
'Snapshot ID',
'Status',
'Created_at',
'Updated_at',
'Share_id',
'Share_instance_id',
'Progress',
'Provider_location',
)
for si in snapshot_instances:
for key in expected_keys:
self.assertIn(key, si)
for key in ('ID', 'Snapshot ID', 'Share_id', 'Share_instance_id'):
self.assertTrue(uuidutils.is_uuid_like(si[key]))
def test_list_snapshot_instance_with_snapshot(self):
snapshot_instances = self.admin_client.list_snapshot_instances(
snapshot_id=self.snapshot['id']
)
self.assertEqual(1, len(snapshot_instances))
expected_keys = ('ID', 'Snapshot ID', 'Status')
for si in snapshot_instances:
for key in expected_keys:
self.assertIn(key, si)
self.assertTrue(uuidutils.is_uuid_like(si['ID']))
self.assertTrue(uuidutils.is_uuid_like(si['Snapshot ID']))
def test_list_snapshot_instance_with_columns(self):
snapshot_instances = self.admin_client.list_snapshot_instances(
self.snapshot['id'], columns='id,status'
)
self.assertGreater(len(snapshot_instances), 0)
expected_keys = ('Id', 'Status')
unexpected_keys = ('Snapshot ID',)
for si in snapshot_instances:
for key in expected_keys:
self.assertIn(key, si)
for key in unexpected_keys:
self.assertNotIn(key, si)
self.assertTrue(uuidutils.is_uuid_like(si['Id']))
def test_get_snapshot_instance(self):
snapshot_instances = self.admin_client.list_snapshot_instances(
self.snapshot['id']
)
snapshot_instance = self.admin_client.get_snapshot_instance(
snapshot_instances[0]['ID']
)
self.assertGreater(len(snapshot_instance), 0)
expected_keys = (
'id',
'snapshot_id',
'status',
'created_at',
'updated_at',
'share_id',
'share_instance_id',
'progress',
'provider_location',
)
for key in expected_keys:
self.assertIn(key, snapshot_instance)
for key in ('id', 'snapshot_id', 'share_id', 'share_instance_id'):
self.assertTrue(uuidutils.is_uuid_like(snapshot_instance[key]))
def test_snapshot_instance_reset_state(self):
snapshot_instances = self.admin_client.list_snapshot_instances(
self.snapshot['id']
)
self.admin_client.reset_snapshot_instance(
snapshot_instances[0]['ID'], 'error'
)
snapshot_instance = self.admin_client.get_snapshot_instance(
snapshot_instances[0]['ID']
)
self.assertEqual('error', snapshot_instance['status'])
self.admin_client.reset_snapshot_instance(
snapshot_instance['id'], 'available'
)

View File

@@ -1,131 +0,0 @@
# Copyright (c) 2017 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 oslo_utils import uuidutils
import testtools
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
@utils.skip_if_microversion_not_supported('2.32')
class SnapshotInstanceExportLocationReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.share = self.create_share(client=self.get_user_client())
self.snapshot = self.create_snapshot(
share=self.share['id'], client=self.get_user_client()
)
def test_get_snapshot_instance_export_location(self):
client = self.admin_client
snapshot_instances = client.list_snapshot_instances(
self.snapshot['id']
)
self.assertGreater(len(snapshot_instances), 0)
self.assertIn('ID', snapshot_instances[0])
self.assertTrue(uuidutils.is_uuid_like(snapshot_instances[0]['ID']))
snapshot_instance_id = snapshot_instances[0]['ID']
export_locations = client.list_snapshot_instance_export_locations(
snapshot_instance_id
)
el = client.get_snapshot_instance_export_location(
snapshot_instance_id, export_locations[0]['ID']
)
expected_keys = [
'path',
'id',
'is_admin_only',
'share_snapshot_instance_id',
'updated_at',
'created_at',
]
for key in expected_keys:
self.assertIn(key, el)
for key, key_el in (
('ID', 'id'),
('Path', 'path'),
('Is Admin only', 'is_admin_only'),
):
self.assertEqual(export_locations[0][key], el[key_el])
self.assertTrue(
uuidutils.is_uuid_like(el['share_snapshot_instance_id'])
)
self.assertTrue(uuidutils.is_uuid_like(el['id']))
self.assertIn(el['is_admin_only'], ('True', 'False'))
def test_list_snapshot_instance_export_locations(self):
client = self.admin_client
snapshot_instances = client.list_snapshot_instances(
self.snapshot['id']
)
self.assertGreater(len(snapshot_instances), 0)
self.assertIn('ID', snapshot_instances[0])
self.assertTrue(uuidutils.is_uuid_like(snapshot_instances[0]['ID']))
snapshot_instance_id = snapshot_instances[0]['ID']
export_locations = client.list_snapshot_instance_export_locations(
snapshot_instance_id
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('ID', 'Path', 'Is Admin only')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['ID']))
def test_list_snapshot_instance_export_locations_with_columns(self):
client = self.admin_client
snapshot_instances = client.list_snapshot_instances(
self.snapshot['id']
)
self.assertGreater(len(snapshot_instances), 0)
self.assertIn('ID', snapshot_instances[0])
self.assertTrue(uuidutils.is_uuid_like(snapshot_instances[0]['ID']))
snapshot_instance_id = snapshot_instances[0]['ID']
export_locations = client.list_snapshot_instance_export_locations(
snapshot_instance_id, columns='id,path'
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('Id', 'Path')
unexpected_keys = ('Updated At', 'Created At', 'Is Admin only')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
for key in unexpected_keys:
self.assertNotIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['Id']))

View File

@@ -1,96 +0,0 @@
# Copyright (c) 2017 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 oslo_utils import uuidutils
import testtools
from manilaclient import config
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
CONF = config.CONF
@ddt.ddt
@testtools.skipUnless(
CONF.run_snapshot_tests and CONF.run_mount_snapshot_tests,
"Snapshots or mountable snapshots tests are disabled.",
)
@utils.skip_if_microversion_not_supported('2.32')
class SnapshotExportLocationReadWriteTest(base.BaseTestCase):
def setUp(self):
super().setUp()
self.share = self.create_share(client=self.get_user_client())
self.snapshot = self.create_snapshot(
share=self.share['id'], client=self.get_user_client()
)
@ddt.data('admin', 'user')
def test_get_snapshot_export_location(self, role):
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_snapshot_export_locations(
self.snapshot['id']
)
el = client.get_snapshot_export_location(
self.snapshot['id'], export_locations[0]['ID']
)
expected_keys = ['path', 'id', 'updated_at', 'created_at']
if role == 'admin':
expected_keys.extend(
['is_admin_only', 'share_snapshot_instance_id']
)
self.assertTrue(
uuidutils.is_uuid_like(el['share_snapshot_instance_id'])
)
self.assertIn(el['is_admin_only'], ('True', 'False'))
self.assertTrue(uuidutils.is_uuid_like(el['id']))
for key in expected_keys:
self.assertIn(key, el)
@ddt.data('admin', 'user')
def test_list_snapshot_export_locations(self, role):
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_snapshot_export_locations(
self.snapshot['id']
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('ID', 'Path')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['ID']))
@ddt.data('admin', 'user')
def test_list_snapshot_export_locations_with_columns(self, role):
client = self.admin_client if role == 'admin' else self.user_client
export_locations = client.list_snapshot_export_locations(
self.snapshot['id'], columns='id,path'
)
self.assertGreater(len(export_locations), 0)
expected_keys = ('Id', 'Path')
unexpected_keys = ('Updated At', 'Created At')
for el in export_locations:
for key in expected_keys:
self.assertIn(key, el)
for key in unexpected_keys:
self.assertNotIn(key, el)
self.assertTrue(uuidutils.is_uuid_like(el['Id']))

View File

@@ -1,556 +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 io
import re
import sys
from unittest import mock
import ddt
import fixtures
from tempest.lib.cli import output_parser
from testtools import matchers
import manilaclient
from manilaclient.common import cliutils
from manilaclient.common import constants
from manilaclient import exceptions
from manilaclient import shell
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
@ddt.ddt
class OpenstackManilaShellTest(utils.TestCase):
FAKE_ENV = {
'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_TENANT_NAME': 'tenant_name',
'OS_AUTH_URL': 'http://no.where',
}
# Patch os.environ to avoid required auth info.
def set_env_vars(self, env_vars):
for k, v in env_vars.items():
self.useFixture(fixtures.EnvironmentVariable(k, v))
def shell_discover_client(
self,
current_client,
os_api_version,
os_endpoint_type,
os_service_type,
client_args,
):
return current_client, manilaclient.API_MAX_VERSION
def shell(self, argstr):
orig = sys.stdout
try:
sys.stdout = io.StringIO()
_shell = shell.OpenStackManilaShell()
_shell._discover_client = self.shell_discover_client
_shell.main(argstr.split())
except SystemExit:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.assertEqual(exc_value.code, 0)
finally:
out = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
return out
@ddt.data(
{},
{'OS_AUTH_URL': 'http://foo.bar'},
{'OS_AUTH_URL': 'http://foo.bar', 'OS_USERNAME': 'foo'},
{
'OS_AUTH_URL': 'http://foo.bar',
'OS_USERNAME': 'foo_user',
'OS_PASSWORD': 'foo_password',
},
{
'OS_TENANT_NAME': 'foo_tenant',
'OS_USERNAME': 'foo_user',
'OS_PASSWORD': 'foo_password',
},
{'OS_TOKEN': 'foo_token'},
{'OS_MANILA_BYPASS_URL': 'http://foo.foo'},
)
def test_main_failure(self, env_vars):
self.set_env_vars(env_vars)
with mock.patch.object(shell, 'client') as mock_client:
self.assertRaises(exceptions.CommandError, self.shell, 'list')
self.assertFalse(mock_client.Client.called)
@ddt.data(None, 'foo_key')
def test_main_success(self, os_key):
env_vars = {
'OS_AUTH_URL': 'http://foo.bar',
'OS_USERNAME': 'foo_username',
'OS_USER_ID': 'foo_user_id',
'OS_PASSWORD': 'foo_password',
'OS_TENANT_NAME': 'foo_tenant',
'OS_TENANT_ID': 'foo_tenant_id',
'OS_PROJECT_NAME': 'foo_project',
'OS_PROJECT_ID': 'foo_project_id',
'OS_PROJECT_DOMAIN_ID': 'foo_project_domain_id',
'OS_PROJECT_DOMAIN_NAME': 'foo_project_domain_name',
'OS_USER_DOMAIN_NAME': 'foo_user_domain_name',
'OS_USER_DOMAIN_ID': 'foo_user_domain_id',
'OS_CERT': 'foo_cert',
'OS_KEY': os_key,
}
self.set_env_vars(env_vars)
cert = env_vars['OS_CERT']
if os_key:
cert = (cert, env_vars['OS_KEY'])
with mock.patch.object(shell, 'client') as mock_client:
self.shell('list')
mock_client.Client.assert_called_with(
manilaclient.API_MAX_VERSION,
username=env_vars['OS_USERNAME'],
password=env_vars['OS_PASSWORD'],
project_name=env_vars['OS_PROJECT_NAME'],
auth_url=env_vars['OS_AUTH_URL'],
insecure=False,
region_name='',
tenant_id=env_vars['OS_PROJECT_ID'],
endpoint_type='publicURL',
extensions=mock.ANY,
service_type=constants.V2_SERVICE_TYPE,
service_name='',
retries=0,
http_log_debug=False,
cacert=None,
use_keyring=False,
force_new_token=False,
user_id=env_vars['OS_USER_ID'],
user_domain_id=env_vars['OS_USER_DOMAIN_ID'],
user_domain_name=env_vars['OS_USER_DOMAIN_NAME'],
project_domain_id=env_vars['OS_PROJECT_DOMAIN_ID'],
project_domain_name=env_vars['OS_PROJECT_DOMAIN_NAME'],
cert=cert,
input_auth_token='',
service_catalog_url='',
)
@ddt.data(
{
"env_vars": {
"OS_MANILA_BYPASS_URL": "http://foo.url",
"OS_TOKEN": "foo_token",
},
"kwargs": {
"--os-token": "bar_token",
"--bypass-url": "http://bar.url",
},
"expected": {
"input_auth_token": "bar_token",
"service_catalog_url": "http://bar.url",
},
},
{
"env_vars": {
"OS_MANILA_BYPASS_URL": "http://foo.url",
"OS_TOKEN": "foo_token",
},
"kwargs": {},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://foo.url",
},
},
{
"env_vars": {},
"kwargs": {
"--os-token": "bar_token",
"--bypass-url": "http://bar.url",
},
"expected": {
"input_auth_token": "bar_token",
"service_catalog_url": "http://bar.url",
},
},
{
"env_vars": {
"MANILACLIENT_BYPASS_URL": "http://foo.url",
"OS_TOKEN": "foo_token",
},
"kwargs": {},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://foo.url",
},
},
{
"env_vars": {"OS_TOKEN": "foo_token"},
"kwargs": {"--bypass-url": "http://bar.url"},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://bar.url",
},
},
{
"env_vars": {
"MANILACLIENT_BYPASS_URL": "http://foo.url",
"OS_MANILA_BYPASS_URL": "http://bar.url",
"OS_TOKEN": "foo_token",
},
"kwargs": {"--os-token": "bar_token"},
"expected": {
"input_auth_token": "bar_token",
"service_catalog_url": "http://bar.url",
},
},
)
@ddt.unpack
def test_main_success_with_token(self, env_vars, kwargs, expected):
self.set_env_vars(env_vars)
with mock.patch.object(shell, "client") as mock_client:
cmd = ""
for k, v in kwargs.items():
cmd += f"{k}={v} "
cmd += "list"
self.shell(cmd)
mock_client.Client.assert_called_with(
manilaclient.API_MAX_VERSION,
username="",
password="",
project_name="",
auth_url="",
insecure=False,
region_name="",
tenant_id="",
endpoint_type="publicURL",
extensions=mock.ANY,
service_type=constants.V2_SERVICE_TYPE,
service_name="",
retries=0,
http_log_debug=False,
cacert=None,
use_keyring=False,
force_new_token=False,
user_id="",
user_domain_id="",
user_domain_name="",
project_domain_id="",
project_domain_name="",
cert=None,
input_auth_token=expected["input_auth_token"],
service_catalog_url=expected["service_catalog_url"],
)
@ddt.data(
# default without any env var or kwargs
{
"env_vars": {
"OS_TOKEN": "foo_token",
"OS_MANILA_BYPASS_URL": "http://bar.url",
},
"kwargs": {},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://bar.url",
"os_endpoint_type": "publicURL",
},
},
# only env var
{
"env_vars": {
"OS_TOKEN": "foo_token",
"OS_MANILA_BYPASS_URL": "http://bar.url",
"OS_MANILA_ENDPOINT_TYPE": "custom-endpoint-type",
},
"kwargs": {},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://bar.url",
"os_endpoint_type": "custom-endpoint-type",
},
},
# only kwargs
{
"env_vars": {
"OS_TOKEN": "foo_token",
"OS_MANILA_BYPASS_URL": "http://bar.url",
},
"kwargs": {"--endpoint-type": "custom-kwargs-endpoint-type"},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://bar.url",
"os_endpoint_type": "custom-kwargs-endpoint-type",
},
},
# env var *and* kwargs (kwargs should win)
{
"env_vars": {
"OS_TOKEN": "foo_token",
"OS_MANILA_BYPASS_URL": "http://bar.url",
"os_endpoint_type": "custom-env-endpoint-type",
},
"kwargs": {"--endpoint-type": "custom-kwargs-endpoint-type"},
"expected": {
"input_auth_token": "foo_token",
"service_catalog_url": "http://bar.url",
"os_endpoint_type": "custom-kwargs-endpoint-type",
},
},
)
@ddt.unpack
def test_main_success_with_os_endpoint(self, env_vars, kwargs, expected):
self.set_env_vars(env_vars)
with mock.patch.object(shell, "client") as mock_client:
cmd = ""
for k, v in kwargs.items():
cmd += f"{k}={v} "
cmd += "list"
self.shell(cmd)
mock_client.Client.assert_called_with(
manilaclient.API_MAX_VERSION,
username="",
password="",
project_name="",
auth_url="",
insecure=False,
region_name="",
tenant_id="",
endpoint_type=expected["os_endpoint_type"],
extensions=mock.ANY,
service_type=constants.V2_SERVICE_TYPE,
service_name="",
retries=0,
http_log_debug=False,
cacert=None,
use_keyring=False,
force_new_token=False,
user_id="",
user_domain_id="",
user_domain_name="",
project_domain_id="",
project_domain_name="",
cert=None,
input_auth_token=expected["input_auth_token"],
service_catalog_url=expected["service_catalog_url"],
)
def test_help_unknown_command(self):
self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
@ddt.data('list --help', '--help list', 'help list')
def test_help_on_subcommand(self, cmd):
required = [
'.*?^usage: manila list',
'.*?^List NAS shares with filters.',
]
help_text = self.shell(cmd)
for r in required:
self.assertThat(
help_text, matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE)
)
def test_common_args_in_help_message(self):
expected_args = (
'--version',
'',
'--debug',
'--os-cache',
'--os-reset-cache',
'--os-user-id',
'--os-username',
'--os-password',
'--os-tenant-name',
'--os-project-name',
'--os-tenant-id',
'--os-project-id',
'--os-user-domain-id',
'--os-user-domain-name',
'--os-project-domain-id',
'--os-project-domain-name',
'--os-auth-url',
'--os-region-name',
'--service-type',
'--service-name',
'--share-service-name',
'--endpoint-type',
'--os-share-api-version',
'--os-cacert',
'--retries',
'--os-cert',
'--os-key',
)
help_text = self.shell('help')
for expected_arg in expected_args:
self.assertIn(expected_arg, help_text)
class CustomOpenStackManilaShell(shell.OpenStackManilaShell):
@staticmethod
@cliutils.arg(
'--default-is-none',
'--default_is_none',
type=str,
metavar='<redefined_metavar>',
action='single_alias',
help='Default value is None and metavar set.',
default=None,
)
def do_foo(cs, args):
cliutils.print_dict({'key': args.default_is_none})
@staticmethod
@cliutils.arg(
'--default-is-not-none',
'--default_is_not_none',
type=str,
action='single_alias',
help='Default value is not None and metavar not set.',
default='bar',
)
def do_bar(cs, args):
cliutils.print_dict({'key': args.default_is_not_none})
@staticmethod
@cliutils.arg(
'--list-like',
'--list_like',
nargs='*',
action='single_alias',
help='Default value is None, metavar not set and result is list.',
default=None,
)
def do_quuz(cs, args):
cliutils.print_dict({'key': args.list_like})
@ddt.ddt
class AllowOnlyOneAliasAtATimeActionTest(utils.TestCase):
FAKE_ENV = {
'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_TENANT_NAME': 'tenant_name',
'OS_AUTH_URL': 'http://no.where',
}
def setUp(self):
super(self.__class__, self).setUp()
for k, v in self.FAKE_ENV.items():
self.useFixture(fixtures.EnvironmentVariable(k, v))
self.mock_object(
shell.client,
'get_client_class',
mock.Mock(return_value=fakes.FakeClient),
)
def shell_discover_client(
self,
current_client,
os_api_version,
os_endpoint_type,
os_service_type,
client_args,
):
return current_client, manilaclient.API_MAX_VERSION
def shell(self, argstr):
orig = sys.stdout
try:
sys.stdout = io.StringIO()
_shell = CustomOpenStackManilaShell()
_shell._discover_client = self.shell_discover_client
_shell.main(argstr.split())
except SystemExit:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.assertEqual(exc_value.code, 0)
finally:
out = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
return out
@ddt.data(
('--default-is-none foo', 'foo'),
('--default-is-none foo --default-is-none foo', 'foo'),
('--default-is-none foo --default_is_none foo', 'foo'),
('--default_is_none None', 'None'),
)
@ddt.unpack
def test_foo_success(self, options_str, expected_result):
output = self.shell(f'foo {options_str}')
parsed_output = output_parser.details(output)
self.assertEqual({'key': expected_result}, parsed_output)
@ddt.data(
'--default-is-none foo --default-is-none bar',
'--default-is-none foo --default_is_none bar',
'--default-is-none foo --default_is_none FOO',
)
def test_foo_error(self, options_str):
self.assertRaises(
matchers.MismatchError, self.shell, f'foo {options_str}'
)
@ddt.data(
('--default-is-not-none bar', 'bar'),
('--default_is_not_none bar --default-is-not-none bar', 'bar'),
('--default_is_not_none bar --default_is_not_none bar', 'bar'),
('--default-is-not-none not_bar', 'not_bar'),
('--default_is_not_none None', 'None'),
)
@ddt.unpack
def test_bar_success(self, options_str, expected_result):
output = self.shell(f'bar {options_str}')
parsed_output = output_parser.details(output)
self.assertEqual({'key': expected_result}, parsed_output)
@ddt.data(
'--default-is-not-none foo --default-is-not-none bar',
'--default-is-not-none foo --default_is_not_none bar',
'--default-is-not-none bar --default_is_not_none BAR',
)
def test_bar_error(self, options_str):
self.assertRaises(
matchers.MismatchError, self.shell, f'bar {options_str}'
)
@ddt.data(
('--list-like q=w', "['q=w']"),
('--list-like q=w --list_like q=w', "['q=w']"),
(
'--list-like q=w e=r t=y --list_like e=r t=y q=w',
"['e=r', 'q=w', 't=y']",
),
('--list_like q=w e=r t=y', "['e=r', 'q=w', 't=y']"),
)
@ddt.unpack
def test_quuz_success(self, options_str, expected_result):
output = self.shell(f'quuz {options_str}')
parsed_output = output_parser.details(output)
self.assertEqual({'key': expected_result}, parsed_output)
@ddt.data(
'--list-like q=w --list_like e=r t=y',
)
def test_quuz_error(self, options_str):
self.assertRaises(
matchers.MismatchError, self.shell, f'quuz {options_str}'
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -30,9 +30,6 @@ classifiers = [
Homepage = "https://docs.openstack.org/python-manilaclient/"
Repository = "https://opendev.org/openstack/python-manilaclient/"
[project.scripts]
manila = "manilaclient.shell:main"
[project.entry-points."oslo.config.opts"]
"manilaclient.config" = "manilaclient.config:list_opts"

View File

@@ -0,0 +1,5 @@
---
upgrade:
The "manila" CLI utility has been removed in this release. The
mapping/decoder documentation still exists to provide transition
to users that are unfamiliar with the "openstack" CLI.

View File

@@ -1,15 +0,0 @@
_manila()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="$(manila bash_completion)"
COMPLETION_CACHE=~/.cache/manilaclient/*/*-cache
opts+=" "$(cat $COMPLETION_CACHE 2> /dev/null | tr '\n' ' ')
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
}
complete -F _manila manila