Merge "Remove the legacy "manila" CLI"
This commit is contained in:
@@ -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::
|
||||
|
||||
@@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
@@ -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()
|
||||
@@ -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
@@ -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'])
|
||||
@@ -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')
|
||||
@@ -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])
|
||||
@@ -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')
|
||||
@@ -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'])
|
||||
@@ -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")
|
||||
@@ -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'
|
||||
)
|
||||
@@ -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])
|
||||
@@ -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')
|
||||
@@ -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)
|
||||
@@ -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'],
|
||||
)
|
||||
@@ -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'
|
||||
@@ -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])
|
||||
@@ -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'])
|
||||
@@ -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)
|
||||
@@ -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'])
|
||||
@@ -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)
|
||||
@@ -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'
|
||||
@@ -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)
|
||||
)
|
||||
@@ -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])
|
||||
@@ -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)
|
||||
@@ -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'
|
||||
)
|
||||
@@ -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']))
|
||||
@@ -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']))
|
||||
@@ -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
@@ -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"
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user