Add support of new API URLs after port of extensions to core API

Make manilaclient support API URLs and actions rename after port of
extensions to core API.

Depends-on: I82f00114db985b4b3bf4db0a64191559508ac600

Implements bp ext-to-core

Change-Id: I44f71ca094f230f3c22ade241884a1b23865c81a
This commit is contained in:
Valeriy Ponomaryov 2015-11-11 12:50:01 +02:00
parent c34e3b7d2c
commit 28263b936d
30 changed files with 1492 additions and 534 deletions

View File

@ -31,7 +31,7 @@ if not LOG.handlers:
LOG.addHandler(logging.StreamHandler())
MAX_VERSION = '2.6'
MAX_VERSION = '2.7'
MIN_VERSION = '2.0'
DEPRECATED_VERSION = '1.0'
_VERSIONED_METHOD_MAP = {}

View File

@ -19,6 +19,8 @@ import os
from oslo_config import cfg
import oslo_log._options as log_options
from manilaclient import api_versions
# 1. Define opts
# "auth_opts" are used by functional tests that are located in
@ -67,6 +69,17 @@ base_opts = [
]
share_opts = [
cfg.StrOpt("min_api_microversion",
default="1.0",
help="The minimum API microversion is configured to be the "
"value of the minimum microversion supported by "
"Manilaclient functional tests. Defaults to 1.0."),
cfg.StrOpt("max_api_microversion",
default=api_versions.MAX_VERSION,
help="The maximum API microversion is configured to be the "
"value of the latest microversion supported by "
"Manilaclient functional tests. Defaults to "
"manilaclient's max supported API microversion."),
cfg.StrOpt("share_network",
default=None,
help="Share network Name or ID, that will be used for shares. "

View File

@ -21,6 +21,7 @@ from tempest_lib import exceptions as lib_exc
from manilaclient import config
from manilaclient.tests.functional import client
from manilaclient.tests.functional import utils
CONF = config.CONF
LOG = log.getLogger(__name__)
@ -85,19 +86,25 @@ class BaseTestCase(base.ClientTestBase):
if "client" not in res:
res["client"] = cls.get_cleanup_client()
if not(res["deleted"]):
res_id = res['id']
res_id = res["id"]
client = res["client"]
with handle_cleanup_exceptions():
# TODO(vponomaryov): add support for other resources
if res["type"] is "share_type":
client.delete_share_type(res_id)
client.wait_for_share_type_deletion(res_id)
client.delete_share_type(
res_id, microversion=res["microversion"])
client.wait_for_share_type_deletion(
res_id, microversion=res["microversion"])
elif res["type"] is "share_network":
client.delete_share_network(res_id)
client.wait_for_share_network_deletion(res_id)
client.delete_share_network(
res_id, microversion=res["microversion"])
client.wait_for_share_network_deletion(
res_id, microversion=res["microversion"])
elif res["type"] is "share":
client.delete_share(res_id)
client.wait_for_share_deletion(res_id)
client.delete_share(
res_id, microversion=res["microversion"])
client.wait_for_share_deletion(
res_id, microversion=res["microversion"])
else:
LOG.warn("Provided unsupported resource type for "
"cleanup '%s'. Skipping." % res["type"])
@ -142,21 +149,29 @@ class BaseTestCase(base.ClientTestBase):
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(
"Microversion '%s' is not supported." % microversion)
@classmethod
def create_share_type(cls, name=None, driver_handles_share_servers=True,
snapshot_support=True,
is_public=True, client=None, cleanup_in_class=True):
snapshot_support=True, is_public=True, client=None,
cleanup_in_class=True, microversion=None):
if client is None:
client = cls.get_admin_client()
share_type = client.create_share_type(
name=name,
driver_handles_share_servers=driver_handles_share_servers,
snapshot_support=snapshot_support,
is_public=is_public)
is_public=is_public,
microversion=microversion,
)
resource = {
"type": "share_type",
"id": share_type["ID"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
@ -168,7 +183,7 @@ class BaseTestCase(base.ClientTestBase):
def create_share_network(cls, name=None, description=None,
nova_net_id=None, neutron_net_id=None,
neutron_subnet_id=None, client=None,
cleanup_in_class=True):
cleanup_in_class=True, microversion=None):
if client is None:
client = cls.get_admin_client()
share_network = client.create_share_network(
@ -176,11 +191,14 @@ class BaseTestCase(base.ClientTestBase):
description=description,
nova_net_id=nova_net_id,
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id)
neutron_subnet_id=neutron_subnet_id,
microversion=microversion,
)
resource = {
"type": "share_network",
"id": share_network["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
@ -193,7 +211,7 @@ class BaseTestCase(base.ClientTestBase):
share_type=None, name=None, description=None,
public=False, snapshot=None, metadata=None,
client=None, cleanup_in_class=False,
wait_for_creation=True):
wait_for_creation=True, microversion=None):
if client is None:
client = cls.get_admin_client()
data = {
@ -204,6 +222,7 @@ class BaseTestCase(base.ClientTestBase):
'public': public,
'snapshot': snapshot,
'metadata': metadata,
'microversion': microversion,
}
share_network = share_network or client.share_network
share_type = share_type or CONF.share_type
@ -216,6 +235,7 @@ class BaseTestCase(base.ClientTestBase):
"type": "share",
"id": share["id"],
"client": client,
"microversion": microversion,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
@ -229,7 +249,7 @@ class BaseTestCase(base.ClientTestBase):
def create_security_service(cls, type='ldap', name=None, description=None,
dns_ip=None, server=None, domain=None,
user=None, password=None, client=None,
cleanup_in_class=False):
cleanup_in_class=False, microversion=None):
if client is None:
client = cls.get_admin_client()
data = {
@ -241,12 +261,14 @@ class BaseTestCase(base.ClientTestBase):
'server': server,
'domain': domain,
'dns_ip': dns_ip,
'microversion': microversion,
}
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)

View File

@ -74,12 +74,14 @@ class ManilaCLIClient(base.CLIClient):
self.build_timeout = CONF.build_timeout
def manila(self, action, flags='', params='', fail_ok=False,
endpoint_type='publicURL', merge_stderr=False):
endpoint_type='publicURL', merge_stderr=False,
microversion=None):
"""Executes manila command for the given action.
:param action: the cli command to run using manila
:type action: string
:param flags: any optional cli flags to use
:param flags: any optional cli flags to use. For specifying
microversion, please, use 'microversion' param
:type flags: string
:param params: any optional positional args to use
:type params: string
@ -90,13 +92,24 @@ class ManilaCLIClient(base.CLIClient):
:type endpoint_type: string
:param merge_stderr: if True the stderr buffer is merged into stdout
:type merge_stderr: boolean
:param microversion: API microversion to be used for request
:type microversion: str
"""
flags += ' --endpoint-type %s' % endpoint_type
if not microversion:
# NOTE(vponomaryov): use max API version from config
microversion = CONF.max_api_microversion
# NOTE(vponomaryov): it is possible that param 'flags' already
# can contain '--os-share-api-version' key. If it is so and we
# reached this part then value of 'microversion' param will be
# used and existing one in 'flags' param will be ignored.
flags += ' --os-share-api-version %s' % microversion
return self.cmd_with_auth(
'manila', action, flags, params, fail_ok, merge_stderr)
def wait_for_resource_deletion(self, res_type, res_id, interval=3,
timeout=180):
timeout=180, microversion=None):
"""Resource deletion waiter.
:param res_type: text -- type of resource. Supported only 'share_type'.
@ -116,11 +129,11 @@ class ManilaCLIClient(base.CLIClient):
raise exceptions.InvalidResource(message=res_type)
end_loop_time = time.time() + timeout
deleted = func(res_id)
deleted = func(res_id, microversion=microversion)
while not (deleted or time.time() > end_loop_time):
time.sleep(interval)
deleted = func(res_id)
deleted = func(res_id, microversion=microversion)
if not deleted:
raise exceptions.ResourceReleaseFailed(
@ -129,7 +142,8 @@ class ManilaCLIClient(base.CLIClient):
# Share types
def create_share_type(self, name=None, driver_handles_share_servers=True,
snapshot_support=True, is_public=True):
snapshot_support=True, is_public=True,
microversion=None):
"""Creates share type.
:param name: text -- name of share type to use, if not set then
@ -154,7 +168,7 @@ class ManilaCLIClient(base.CLIClient):
'--snapshot-support %(snapshot_support)s') % {
'name': name, 'dhss': dhss, 'is_public': is_public,
'snapshot_support': snapshot_support}
share_type_raw = self.manila(cmd)
share_type_raw = self.manila(cmd, microversion=microversion)
# NOTE(vponomaryov): share type creation response is "list"-like with
# only one element:
@ -169,11 +183,12 @@ class ManilaCLIClient(base.CLIClient):
return share_type
@not_found_wrapper
def delete_share_type(self, share_type):
def delete_share_type(self, share_type, microversion=None):
"""Deletes share type by its Name or ID."""
return self.manila('type-delete %s' % share_type)
return self.manila(
'type-delete %s' % share_type, microversion=microversion)
def list_share_types(self, list_all=True):
def list_share_types(self, list_all=True, microversion=None):
"""List share types.
:param list_all: bool -- whether to list all share types or only public
@ -181,41 +196,43 @@ class ManilaCLIClient(base.CLIClient):
cmd = 'type-list'
if list_all:
cmd += ' --all'
share_types_raw = self.manila(cmd)
share_types_raw = self.manila(cmd, microversion=microversion)
share_types = output_parser.listing(share_types_raw)
return share_types
def get_share_type(self, share_type):
def get_share_type(self, share_type, microversion=None):
"""Get share type.
:param share_type: str -- Name or ID of share type
"""
share_types = self.list_share_types(True)
share_types = self.list_share_types(True, microversion=microversion)
for st in share_types:
if share_type in (st['ID'], st['Name']):
return st
raise tempest_lib_exc.NotFound()
def is_share_type_deleted(self, share_type):
def is_share_type_deleted(self, share_type, microversion=None):
"""Says whether share type is deleted or not.
:param share_type: text -- Name or ID of share type
"""
# NOTE(vponomaryov): we use 'list' operation because there is no
# 'get/show' operation for share-types available for CLI
share_types = self.list_share_types(list_all=True)
share_types = self.list_share_types(
list_all=True, microversion=microversion)
for list_element in share_types:
if share_type in (list_element['ID'], list_element['Name']):
return False
return True
def wait_for_share_type_deletion(self, share_type):
def wait_for_share_type_deletion(self, share_type, microversion=None):
"""Wait for share type deletion by its Name or ID.
:param share_type: text -- Name or ID of share type
"""
self.wait_for_resource_deletion(
SHARE_TYPE, res_id=share_type, interval=2, timeout=6)
SHARE_TYPE, res_id=share_type, interval=2, timeout=6,
microversion=microversion)
def get_project_id(self, name_or_id):
try:
@ -228,24 +245,30 @@ class ManilaCLIClient(base.CLIClient):
return project_id.strip()
@not_found_wrapper
def add_share_type_access(self, share_type_name_or_id, project_id):
def add_share_type_access(self, share_type_name_or_id, project_id,
microversion=None):
data = dict(st=share_type_name_or_id, project=project_id)
self.manila('type-access-add %(st)s %(project)s' % data)
self.manila('type-access-add %(st)s %(project)s' % data,
microversion=microversion)
@not_found_wrapper
def remove_share_type_access(self, share_type_name_or_id, project_id):
def remove_share_type_access(self, share_type_name_or_id, project_id,
microversion=None):
data = dict(st=share_type_name_or_id, project=project_id)
self.manila('type-access-remove %(st)s %(project)s' % data)
self.manila('type-access-remove %(st)s %(project)s' % data,
microversion=microversion)
@not_found_wrapper
def list_share_type_access(self, share_type_id):
projects_raw = self.manila('type-access-list %s' % share_type_id)
def list_share_type_access(self, share_type_id, microversion=None):
projects_raw = self.manila(
'type-access-list %s' % share_type_id, microversion=microversion)
projects = output_parser.listing(projects_raw)
project_ids = [pr['Project_ID'] for pr in projects]
return project_ids
@not_found_wrapper
def set_share_type_extra_specs(self, share_type_name_or_id, extra_specs):
def set_share_type_extra_specs(self, share_type_name_or_id, extra_specs,
microversion=None):
"""Set key-value pair for share type."""
if not (isinstance(extra_specs, dict) and extra_specs):
raise exceptions.InvalidData(
@ -253,29 +276,33 @@ class ManilaCLIClient(base.CLIClient):
cmd = 'type-key %s set ' % share_type_name_or_id
for key, value in extra_specs.items():
cmd += '%(key)s=%(value)s ' % {'key': key, 'value': value}
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
@not_found_wrapper
def unset_share_type_extra_specs(self, share_type_name_or_id,
extra_specs_keys):
extra_specs_keys, microversion=None):
"""Unset key-value pair for share type."""
if not (isinstance(extra_specs_keys, list) and extra_specs_keys):
if not (isinstance(extra_specs_keys, (list, tuple, set)) and
extra_specs_keys):
raise exceptions.InvalidData(
message='Provided invalid extra specs - %s' % extra_specs_keys)
cmd = 'type-key %s unset ' % share_type_name_or_id
for key in extra_specs_keys:
cmd += '%s ' % key
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
def list_all_share_type_extra_specs(self):
def list_all_share_type_extra_specs(self, microversion=None):
"""List extra specs for all share types."""
extra_specs_raw = self.manila('extra-specs-list')
extra_specs_raw = self.manila(
'extra-specs-list', microversion=microversion)
extra_specs = utils.listing(extra_specs_raw)
return extra_specs
def list_share_type_extra_specs(self, share_type_name_or_id):
def list_share_type_extra_specs(self, share_type_name_or_id,
microversion=None):
"""List extra specs for specific share type by its Name or ID."""
all_share_types = self.list_all_share_type_extra_specs()
all_share_types = self.list_all_share_type_extra_specs(
microversion=microversion)
for share_type in all_share_types:
if share_type_name_or_id in (share_type['ID'], share_type['Name']):
return share_type['all_extra_specs']
@ -285,7 +312,7 @@ class ManilaCLIClient(base.CLIClient):
def create_share_network(self, name=None, description=None,
nova_net_id=None, neutron_net_id=None,
neutron_subnet_id=None):
neutron_subnet_id=None, microversion=None):
"""Creates share network.
:param name: text -- desired name of new share network
@ -303,7 +330,8 @@ class ManilaCLIClient(base.CLIClient):
nova_net_id=nova_net_id,
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id)
share_network_raw = self.manila('share-network-create %s' % params)
share_network_raw = self.manila(
'share-network-create %s' % params, microversion=microversion)
share_network = output_parser.details(share_network_raw)
return share_network
@ -331,17 +359,17 @@ class ManilaCLIClient(base.CLIClient):
return cmd
@not_found_wrapper
def get_share_network(self, share_network):
def get_share_network(self, share_network, microversion=None):
"""Returns share network by its Name or ID."""
share_network_raw = self.manila(
'share-network-show %s' % share_network)
'share-network-show %s' % share_network, microversion=microversion)
share_network = output_parser.details(share_network_raw)
return share_network
@not_found_wrapper
def update_share_network(self, share_network, name=None, description=None,
nova_net_id=None, neutron_net_id=None,
neutron_subnet_id=None):
neutron_subnet_id=None, microversion=None):
"""Updates share-network by its name or ID.
:param name: text -- new name for share network
@ -361,14 +389,16 @@ class ManilaCLIClient(base.CLIClient):
neutron_subnet_id=neutron_subnet_id)
share_network_raw = self.manila(
'share-network-update %(sn)s %(params)s' % dict(
sn=share_network, params=sn_params))
sn=share_network, params=sn_params),
microversion=microversion)
share_network = output_parser.details(share_network_raw)
return share_network
@not_found_wrapper
def delete_share_network(self, share_network):
def delete_share_network(self, share_network, microversion=None):
"""Deletes share network by its Name or ID."""
return self.manila('share-network-delete %s' % share_network)
return self.manila('share-network-delete %s' % share_network,
microversion=microversion)
@staticmethod
def _stranslate_to_cli_optional_param(param):
@ -379,7 +409,8 @@ class ManilaCLIClient(base.CLIClient):
param = '-' + param
return param.replace('_', '-')
def list_share_networks(self, all_tenants=False, filters=None):
def list_share_networks(self, all_tenants=False, filters=None,
microversion=None):
"""List share networks.
:param all_tenants: bool -- whether to list share-networks that belong
@ -399,34 +430,37 @@ class ManilaCLIClient(base.CLIClient):
for k, v in filters.items():
cmd += '%(k)s=%(v)s ' % {
'k': self._stranslate_to_cli_optional_param(k), 'v': v}
share_networks_raw = self.manila(cmd)
share_networks_raw = self.manila(cmd, microversion=microversion)
share_networks = utils.listing(share_networks_raw)
return share_networks
def is_share_network_deleted(self, share_network):
def is_share_network_deleted(self, share_network, microversion=None):
"""Says whether share network is deleted or not.
:param share_network: text -- Name or ID of share network
"""
share_types = self.list_share_networks(True)
share_types = self.list_share_networks(True, microversion=microversion)
for list_element in share_types:
if share_network in (list_element['id'], list_element['name']):
return False
return True
def wait_for_share_network_deletion(self, share_network):
def wait_for_share_network_deletion(self, share_network,
microversion=None):
"""Wait for share network deletion by its Name or ID.
:param share_network: text -- Name or ID of share network
"""
self.wait_for_resource_deletion(
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6)
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6,
microversion=microversion)
# Shares
def create_share(self, share_protocol, size, share_network=None,
share_type=None, name=None, description=None,
public=False, snapshot=None, metadata=None):
public=False, snapshot=None, metadata=None,
microversion=None):
"""Creates a share.
:param share_protocol: str -- share protocol of a share.
@ -439,6 +473,7 @@ class ManilaCLIClient(base.CLIClient):
Default is False.
:param snapshot: str -- Name or ID of a snapshot to use as source.
:param metadata: dict -- key-value data to provide with share creation.
:param microversion: str -- API microversion that should be used.
"""
cmd = 'create %(share_protocol)s %(size)s ' % {
'share_protocol': share_protocol, 'size': size}
@ -462,20 +497,20 @@ class ManilaCLIClient(base.CLIClient):
metadata_cli += '%(k)s=%(v)s ' % {'k': k, 'v': v}
if metadata_cli:
cmd += '--metadata %s ' % metadata_cli
share_raw = self.manila(cmd)
share_raw = self.manila(cmd, microversion=microversion)
share = output_parser.details(share_raw)
return share
@not_found_wrapper
def get_share(self, share):
def get_share(self, share, microversion=None):
"""Returns a share by its Name or ID."""
share_raw = self.manila('show %s' % share)
share_raw = self.manila('show %s' % share, microversion=microversion)
share = output_parser.details(share_raw)
return share
@not_found_wrapper
def update_share(self, share, name=None, description=None,
is_public=False):
is_public=False, microversion=None):
"""Updates a share.
:param share: str -- name or ID of a share that should be updated.
@ -492,11 +527,11 @@ class ManilaCLIClient(base.CLIClient):
is_public = strutils.bool_from_string(is_public, strict=True)
cmd += '--is-public %s ' % is_public
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
@not_found_wrapper
@forbidden_wrapper
def delete_share(self, shares):
def delete_share(self, shares, microversion=None):
"""Deletes share[s] by Names or IDs.
:param shares: either str or list of str that can be either Name
@ -507,9 +542,10 @@ class ManilaCLIClient(base.CLIClient):
cmd = 'delete '
for share in shares:
cmd += '%s ' % share
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
def list_shares(self, all_tenants=False, filters=None, columns=None):
def list_shares(self, all_tenants=False, filters=None, columns=None,
microversion=None):
"""List shares.
:param all_tenants: bool -- whether to list shares that belong
@ -533,39 +569,40 @@ class ManilaCLIClient(base.CLIClient):
'k': self._stranslate_to_cli_optional_param(k), 'v': v}
if columns is not None:
cmd += '--columns ' + columns
shares_raw = self.manila(cmd)
shares_raw = self.manila(cmd, microversion=microversion)
shares = utils.listing(shares_raw)
return shares
def is_share_deleted(self, share):
def is_share_deleted(self, share, microversion=None):
"""Says whether share is deleted or not.
:param share: str -- Name or ID of share
"""
try:
self.get_share(share)
self.get_share(share, microversion=microversion)
return False
except tempest_lib_exc.NotFound:
return True
def wait_for_share_deletion(self, share):
def wait_for_share_deletion(self, share, microversion=None):
"""Wait for share deletion by its Name or ID.
:param share: str -- Name or ID of share
"""
self.wait_for_resource_deletion(
SHARE, res_id=share, interval=5, timeout=300)
SHARE, res_id=share, interval=5, timeout=300,
microversion=microversion)
def wait_for_share_status(self, share, status):
def wait_for_share_status(self, share, status, microversion=None):
"""Waits for a share to reach a given status."""
body = self.get_share(share)
body = self.get_share(share, microversion=microversion)
share_name = body['name']
share_status = body['status']
start = int(time.time())
while share_status != status:
time.sleep(self.build_interval)
body = self.get_share(share)
body = self.get_share(share, microversion=microversion)
share_status = body['status']
if share_status == status:
@ -582,7 +619,8 @@ class ManilaCLIClient(base.CLIClient):
raise tempest_lib_exc.TimeoutException(message)
@not_found_wrapper
def _set_share_metadata(self, share, data, update_all=False):
def _set_share_metadata(self, share, data, update_all=False,
microversion=None):
"""Sets a share metadata.
:param share: str -- Name or ID of a share.
@ -600,18 +638,20 @@ class ManilaCLIClient(base.CLIClient):
cmd = 'metadata %s set ' % share
for k, v in data.items():
cmd += '%(k)s=%(v)s ' % {'k': k, 'v': v}
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
def update_all_share_metadata(self, share, data):
metadata_raw = self._set_share_metadata(share, data, True)
def update_all_share_metadata(self, share, data, microversion=None):
metadata_raw = self._set_share_metadata(
share, data, True, microversion=microversion)
metadata = output_parser.details(metadata_raw)
return metadata
def set_share_metadata(self, share, data):
return self._set_share_metadata(share, data, False)
def set_share_metadata(self, share, data, microversion=None):
return self._set_share_metadata(
share, data, False, microversion=microversion)
@not_found_wrapper
def unset_share_metadata(self, share, keys):
def unset_share_metadata(self, share, keys, microversion=None):
"""Unsets some share metadata by keys.
:param share: str -- Name or ID of a share
@ -624,32 +664,35 @@ class ManilaCLIClient(base.CLIClient):
cmd = 'metadata %s unset ' % share
for key in keys:
cmd += '%s ' % key
return self.manila(cmd)
return self.manila(cmd, microversion=microversion)
@not_found_wrapper
def get_share_metadata(self, share):
def get_share_metadata(self, share, microversion=None):
"""Returns list of all share metadata.
:param share: str -- Name or ID of a share.
"""
metadata_raw = self.manila('metadata-show %s' % share)
metadata_raw = self.manila(
'metadata-show %s' % share, microversion=microversion)
metadata = output_parser.details(metadata_raw)
return metadata
@not_found_wrapper
def list_access(self, share_id):
access_list_raw = self.manila('access-list %s' % share_id)
def list_access(self, share_id, microversion=None):
access_list_raw = self.manila(
'access-list %s' % share_id, microversion=microversion)
return output_parser.listing(access_list_raw)
@not_found_wrapper
def get_access(self, share_id, access_id):
for access in self.list_access(share_id):
def get_access(self, share_id, access_id, microversion=None):
for access in self.list_access(share_id, microversion=microversion):
if access['id'] == access_id:
return access
raise tempest_lib_exc.NotFound()
@not_found_wrapper
def access_allow(self, share_id, access_type, access_to, access_level):
def access_allow(self, share_id, access_type, access_to, access_level,
microversion=None):
raw_access = self.manila(
'access-allow --access-level %(level)s %(id)s %(type)s '
'%(access_to)s' % {
@ -657,23 +700,29 @@ class ManilaCLIClient(base.CLIClient):
'id': share_id,
'type': access_type,
'access_to': access_to,
})
},
microversion=microversion)
return output_parser.details(raw_access)
@not_found_wrapper
def access_deny(self, share_id, access_id):
self.manila('access-deny %(share_id)s %(access_id)s' % {
'share_id': share_id,
'access_id': access_id,
})
def access_deny(self, share_id, access_id, microversion=None):
return self.manila(
'access-deny %(share_id)s %(access_id)s' % {
'share_id': share_id,
'access_id': access_id,
},
microversion=microversion)
def wait_for_access_rule_status(self, share_id, access_id, state='active'):
access = self.get_access(share_id, access_id)
def wait_for_access_rule_status(self, share_id, access_id, state='active',
microversion=None):
access = self.get_access(
share_id, access_id, microversion=microversion)
start = int(time.time())
while access['state'] != state:
time.sleep(self.build_interval)
access = self.get_access(share_id, access_id)
access = self.get_access(
share_id, access_id, microversion=microversion)
if access['state'] == state:
return
@ -689,9 +738,11 @@ class ManilaCLIClient(base.CLIClient):
"build_timeout": self.build_timeout})
raise tempest_lib_exc.TimeoutException(message)
def wait_for_access_rule_deletion(self, share_id, access_id):
def wait_for_access_rule_deletion(self, share_id, access_id,
microversion=None):
try:
access = self.get_access(share_id, access_id)
access = self.get_access(
share_id, access_id, microversion=microversion)
except tempest_lib_exc.NotFound:
return
@ -699,7 +750,8 @@ class ManilaCLIClient(base.CLIClient):
while True:
time.sleep(self.build_interval)
try:
access = self.get_access(share_id, access_id)
access = self.get_access(
share_id, access_id, microversion=microversion)
except tempest_lib_exc.NotFound:
return
@ -715,7 +767,7 @@ class ManilaCLIClient(base.CLIClient):
def create_security_service(self, type='ldap', name=None, description=None,
dns_ip=None, server=None, domain=None,
user=None, password=None):
user=None, password=None, microversion=None):
"""Creates security service.
:param type: security service type (ldap, kerberos or active_directory)
@ -738,14 +790,15 @@ class ManilaCLIClient(base.CLIClient):
user=user,
password=password)
ss_raw = self.manila(cmd)
ss_raw = self.manila(cmd, microversion=microversion)
security_service = output_parser.details(ss_raw)
return security_service
@not_found_wrapper
def update_security_service(self, security_service, name=None,
description=None, dns_ip=None, server=None,
domain=None, user=None, password=None):
domain=None, user=None, password=None,
microversion=None):
cmd = 'security-service-update %s ' % security_service
cmd += self. _combine_security_service_data(
name=name,
@ -755,7 +808,8 @@ class ManilaCLIClient(base.CLIClient):
domain=domain,
user=user,
password=password)
return output_parser.details(self.manila(cmd))
return output_parser.details(
self.manila(cmd, microversion=microversion))
def _combine_security_service_data(self, name=None, description=None,
dns_ip=None, server=None, domain=None,

View File

@ -17,6 +17,7 @@ import ddt
from tempest_lib import exceptions
from manilaclient.tests.functional import base
from manilaclient.tests.functional import utils
@ddt.ddt
@ -25,7 +26,7 @@ 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'])
self.assertTableStruct(roles, ('Property', 'Value'))
def test_quota_class_show_by_user(self):
self.assertRaises(
@ -34,13 +35,47 @@ class ManilaClientTestQuotasReadOnly(base.BaseTestCase):
'quota-class-show',
params='abc')
@ddt.data('admin', 'user')
def test_quota_defaults(self, role):
roles = self.parser.listing(
self.clients[role].manila('quota-defaults'))
self.assertTableStruct(roles, ['Property', 'Value'])
def _get_quotas(self, role, operation, microversion):
roles = self.parser.listing(self.clients[role].manila(
'quota-%s' % operation, microversion=microversion))
self.assertTableStruct(roles, ('Property', 'Value'))
@ddt.data('admin', 'user')
def test_quota_show(self, role):
roles = self.parser.listing(self.clients[role].manila('quota-show'))
self.assertTableStruct(roles, ['Property', 'Value'])
@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")

View File

@ -21,8 +21,10 @@ from manilaclient.tests.functional import base
@ddt.ddt
class ManilaClientTestServicesReadOnly(base.BaseTestCase):
def test_services_list(self):
self.clients['admin'].manila('service-list')
@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')

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from tempest_lib import exceptions as tempest_lib_exc
from manilaclient import config
@ -21,6 +22,7 @@ from manilaclient.tests.functional import base
CONF = config.CONF
@ddt.ddt
class ShareAccessReadWriteBase(base.BaseTestCase):
protocol = None
access_level = None
@ -47,30 +49,51 @@ class ShareAccessReadWriteBase(base.BaseTestCase):
cls.share = cls.create_share(share_protocol=cls.protocol,
public=True,
cleanup_in_class=True)
cls.share_id = cls.share['id']
# NOTE(vponomaryov): increase following int range when significant
# amount of new tests is added.
int_range = range(20, 50)
cls.access_to = {
'ip': '10.0.0.1',
'user': CONF.username_for_user_rules,
'cert': 'tenant.example.com',
# NOTE(vponomaryov): list of unique values is required for ability
# to create lots of access rules for one share using different
# API microversions.
'ip': ['99.88.77.%d' % 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': ['foo_user_%d' % i for i in int_range],
'cert': ['tenant_%d.example.com' % i for i in int_range],
}
def test_list_access_rule_for_share(self):
access_to = {
'ip': '10.0.0.1',
'user': CONF.username_for_user_rules,
'cert': 'tenant.example.com',
}
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_create_list_access_rule_for_share(self, microversion):
self.skip_if_microversion_not_supported(microversion)
access_type = self.access_types[0]
access = self.user_client.access_allow(self.share['id'], access_type,
access_to[access_type],
self.access_level)
access_list = self.user_client.list_access(self.share['id'])
access = self.user_client.access_allow(
self.share['id'], access_type, self.access_to[access_type].pop(),
self.access_level, 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']]))
def _create_delete_access_rule(self, share_id, access_type, access_to):
access = self.user_client.access_allow(share_id, access_type,
access_to, self.access_level)
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(
"'%(access_type)s' access rules is disabled for protocol "
"'%(protocol)s'." % {"access_type": access_type,
"protocol": 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'))
@ -85,25 +108,20 @@ class ShareAccessReadWriteBase(base.BaseTestCase):
self.assertRaises(tempest_lib_exc.NotFound,
self.user_client.get_access, share_id, access['id'])
def test_create_delete_ip_access_rule(self):
if 'ip' not in self.access_types:
raise self.skipException("IP access rule is disabled for protocol "
"%s." % self.protocol)
self._create_delete_access_rule(self.share['id'], 'ip', '10.0.0.1')
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_create_delete_ip_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'ip', self.access_to['ip'].pop(), microversion)
def test_create_delete_user_access_rule(self):
if 'user' not in self.access_types:
raise self.skipException("User access rule is disabled for "
"protocol %s." % self.protocol)
self._create_delete_access_rule(self.share['id'], 'user',
CONF.username_for_user_rules)
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_create_delete_user_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'user', CONF.username_for_user_rules, microversion)
def test_create_delete_cert_access_rule(self):
if 'cert' not in self.access_types:
raise self.skipException("Cert access rule is disabled for "
"protocol %s." % self.protocol)
self._create_delete_access_rule(self.share['id'], 'cert',
'tenant.example.com')
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_create_delete_cert_access_rule(self, microversion):
self._create_delete_access_rule(
self.share_id, 'cert', self.access_to['cert'].pop(), microversion)
class NFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):

View File

@ -22,12 +22,25 @@ from manilaclient.tests.functional import base
@ddt.ddt
class ShareTypesReadOnlyTest(base.BaseTestCase):
@ddt.data('admin', 'user')
def test_share_type_list(self, role):
self.clients[role].manila('type-list')
@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)
def test_extra_specs_list(self):
self.admin_client.manila('extra-specs-list')
@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
@ -37,44 +50,50 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
'ID', 'Name', 'Visibility', 'is_default', 'required_extra_specs')
def _share_type_listed_by(self, share_type_id, by_admin=False,
list_all=False):
if by_admin:
client = self.admin_client
else:
client = self.user_client
share_types = client.list_share_types(list_all=list_all)
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):
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)
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))
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))
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))
share_type_id=share_type_id, by_admin=True, list_all=False,
microversion=microversion))
@ddt.data(
{'is_public': True, 'dhss': False},
{'is_public': True, 'dhss': True},
{'is_public': False, 'dhss': True},
{'is_public': False, 'dhss': False},
{'is_public': False, 'dhss': True, 'snapshot_support': False},
{'is_public': False, 'dhss': False, 'snapshot_support': True},
(True, False),
(True, True),
(False, True),
(False, False),
(False, True, False, "2.6"),
(False, False, True, "2.7"),
)
@ddt.unpack
def test_create_delete_share_type(self, is_public, dhss,
snapshot_support=True):
snapshot_support=True,
microversion=None):
if microversion:
self.skip_if_microversion_not_supported(microversion)
share_type_name = data_utils.rand_name('manilaclient_functional_test')
dhss_expected = 'driver_handles_share_servers : %s' % dhss
snapshot_support_expected = 'snapshot_support : %s' % snapshot_support
@ -84,7 +103,9 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
name=share_type_name,
driver_handles_share_servers=dhss,
snapshot_support=snapshot_support,
is_public=is_public)
is_public=is_public,
microversion=microversion,
)
st_id = share_type['ID']
@ -100,20 +121,27 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
self.assertEqual('-', share_type['is_default'])
# Verify its access
self._verify_access(share_type_id=st_id, is_public=is_public)
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)
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)
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)
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_add_remove_access_to_private_share_type(self):
@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
@ -121,20 +149,28 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
share_type = self.create_share_type(
name=share_type_name,
driver_handles_share_servers='False',
is_public=is_public)
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)
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)
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)
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(
@ -143,16 +179,23 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
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)
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)
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)
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)
st_access_list = self.admin_client.list_share_type_access(
st_id, microversion=microversion)
self.assertNotIn(user_project_id, st_access_list)
@ -160,33 +203,42 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
class ShareTypeExtraSpecsReadWriteTest(base.BaseTestCase):
@ddt.data(
{'is_public': True, 'dhss': False},
{'is_public': True, 'dhss': True},
{'is_public': False, 'dhss': True},
{'is_public': False, 'dhss': False},
(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):
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)
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)
st['ID'], st_extra_specs, microversion=microversion)
# View list of extra specs
extra_specs = self.admin_client.list_share_type_extra_specs(st['ID'])
extra_specs = self.admin_client.list_share_type_extra_specs(
st['ID'], microversion=microversion)
for k, v in st_extra_specs.items():
self.assertIn('%s : %s' % (k, v), extra_specs)
# Remove one extra spec
self.admin_client.unset_share_type_extra_specs(st['ID'], ['foo_key'])
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'])
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('driver_handles_share_servers : %s' % dhss, extra_specs)

View File

@ -15,6 +15,11 @@
import six
from tempest_lib.cli import output_parser
import testtools
from manilaclient import config
CONF = config.CONF
def multi_line_row_table(output_lines, group_by_column_index=0):
@ -85,3 +90,19 @@ def listing(output_lines):
item[col_key] = row[col_idx]
items.append(item)
return items
def is_microversion_supported(microversion):
if (float(microversion) > float(CONF.max_api_microversion) or
float(microversion) < float(CONF.min_api_microversion)):
return False
return True
def skip_if_microversion_not_supported(microversion):
"""Decorator for tests that are microversion-specific."""
if not is_microversion_supported(microversion):
reason = ("Skipped. Test requires microversion %s that is not "
"allowed to be used by configuration." % microversion)
return testtools.skip(reason)
return lambda f: f

View File

@ -106,6 +106,8 @@ class FakeHTTPClient(httpclient.HTTPClient):
}
return (200, {}, quota_set)
get_quota_sets_test = get_os_quota_sets_test
def get_os_quota_sets_test_defaults(self):
quota_set = {
'quota_set': {
@ -120,6 +122,8 @@ class FakeHTTPClient(httpclient.HTTPClient):
}
return (200, {}, quota_set)
get_quota_sets_test_defaults = get_os_quota_sets_test_defaults
def put_os_quota_sets_test(self, body, **kw):
assert list(body) == ['quota_set']
fakes.assert_has_keys(body['quota_set'],
@ -137,6 +141,8 @@ class FakeHTTPClient(httpclient.HTTPClient):
}
return (200, {}, quota_set)
put_quota_sets_test = put_os_quota_sets_test
#
# Quota Classes
#
@ -155,6 +161,8 @@ class FakeHTTPClient(httpclient.HTTPClient):
}
return (200, {}, quota_class_set)
get_quota_class_sets_test = get_os_quota_class_sets_test
def put_os_quota_class_sets_test(self, body, **kw):
assert list(body) == ['quota_class_set']
fakes.assert_has_keys(body['quota_class_set'],
@ -172,8 +180,13 @@ class FakeHTTPClient(httpclient.HTTPClient):
}
return (200, {}, quota_class_set)
put_quota_class_sets_test = put_os_quota_class_sets_test
def delete_os_quota_sets_test(self, **kw):
return (202, {}, {})
delete_quota_sets_test = delete_os_quota_sets_test
#
# List all extensions
#

View File

@ -90,14 +90,20 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
}
return (200, {}, services)
get_services = get_os_services
def put_os_services_enable(self, **kw):
return (200, {}, {'host': 'foo', 'binary': 'manila-share',
'disabled': False})
put_services_enable = put_os_services_enable
def put_os_services_disable(self, **kw):
return (200, {}, {'host': 'foo', 'binary': 'manila-share',
'disabled': True})
put_services_disable = put_os_services_disable
def get_v2(self, **kw):
body = {
"versions": [
@ -179,9 +185,10 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
resp = 202
assert len(list(body)) == 1
action = list(body)[0]
if action == 'os-reset_status':
assert 'status' in body['os-reset_status']
elif action == 'os-force_delete':
if action in ('reset_status', 'os-reset_status'):
assert 'status' in body.get(
'reset_status', body.get('os-reset_status'))
elif action in ('force_delete', 'os-force_delete'):
assert body[action] is None
else:
raise AssertionError("Unexpected action: %s" % action)
@ -212,8 +219,9 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
resp = 202
assert len(list(body)) == 1
action = list(body)[0]
if action == 'os-reset_status':
assert 'status' in body['os-reset_status']
if action in ('reset_status', 'os-reset_status'):
assert 'status' in body.get(
'reset_status', body.get('os-reset_status'))
elif action == 'os-force_delete':
assert body[action] is None
else:
@ -260,6 +268,8 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
result = (resp, {}, _body)
return result
post_shares_manage = post_os_share_manage
def post_os_share_unmanage_1234_unmanage(self, **kw):
_body = None
resp = 202
@ -271,23 +281,26 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
resp = 202
assert len(list(body)) == 1
action = list(body)[0]
if action == 'os-allow_access':
if action in ('os-allow_access', 'allow_access'):
expected = ['access_to', 'access_type']
actual = sorted(list(body[action]))
err_msg = "expected '%s', actual is '%s'" % (expected, actual)
assert expected == actual, err_msg
_body = {'access': {}}
elif action == 'os-deny_access':
elif action in ('os-deny_access', 'deny_access'):
assert list(body[action]) == ['access_id']
elif action == 'os-access_list':
elif action in ('os-access_list', 'access_list'):
assert body[action] is None
elif action == 'os-reset_status':
assert 'status' in body['os-reset_status']
elif action == 'os-force_delete':
elif action in ('os-reset_status', 'reset_status'):
assert 'status' in body.get(
'reset_status', body.get('os-reset_status'))
elif action in ('os-force_delete', 'force_delete'):
assert body[action] is None
elif action in ('os-extend', 'os-shrink'):
elif action in ('os-extend', 'os-shrink', 'extend', 'shrink'):
assert body[action] is not None
assert body[action]['new_size'] is not None
elif action in ('unmanage', ):
assert body[action] is None
else:
raise AssertionError("Unexpected share action: %s" % action)
return (resp, {}, _body)
@ -297,13 +310,13 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
resp = 202
assert len(list(body)) == 1
action = list(body)[0]
if action == 'os-allow_access':
if action in ('allow_access', 'os-allow_access'):
expected = ['access_level', 'access_to', 'access_type']
actual = sorted(list(body[action]))
err_msg = "expected '%s', actual is '%s'" % (expected, actual)
assert expected == actual, err_msg
_body = {'access': {}}
elif action == 'os-access_list':
elif action in ('access_list', 'os-access_list'):
assert body[action] is None
_body = {
'access_list': [{
@ -628,6 +641,8 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
'project_id': '00000000-0000-0000-0000-000000000000'}
]})
get_types_3_share_type_access = get_types_3_os_share_type_access
def fake_create(url, body, response_key):
return {'url': url, 'body': body, 'resp_key': response_key}

View File

@ -13,30 +13,61 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
cs = fakes.FakeClient()
from manilaclient.v2 import quota_classes
@ddt.ddt
class QuotaClassSetsTest(utils.TestCase):
def test_class_quotas_get(self):
def _get_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return quota_classes.QuotaClassSetManager(api=mock_microversion)
def _get_resource_path(self, microversion):
if float(microversion) > 2.6:
return quota_classes.RESOURCE_PATH
return quota_classes.RESOURCE_PATH_LEGACY
@ddt.data("2.6", "2.7")
def test_class_quotas_get(self, microversion):
class_name = 'test'
cs.quota_classes.get(class_name)
cs.assert_called('GET', '/os-quota-class-sets/%s' % class_name)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test" % resource_path
with mock.patch.object(manager, '_get',
mock.Mock(return_value='fake_get')):
manager.get(class_name)
def test_update_quota(self):
q = cs.quota_classes.get('test')
q.update(shares=2)
cs.assert_called('PUT', '/os-quota-class-sets/test')
manager._get.assert_called_once_with(
expected_url, "quota_class_set")
def test_refresh_quota(self):
q = cs.quota_classes.get('test')
q2 = cs.quota_classes.get('test')
self.assertEqual(q.shares, q2.shares)
q2.shares = 0
self.assertNotEqual(q.shares, q2.shares)
q2.get()
self.assertEqual(q.shares, q2.shares)
@ddt.data("2.6", "2.7")
def test_update_quota(self, microversion):
class_name = 'test'
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test" % resource_path
expected_body = {
'quota_class_set': {
'class_name': class_name,
'shares': 1,
'snapshots': 2,
'gigabytes': 3,
'snapshot_gigabytes': 4,
'share_networks': 5,
},
}
with mock.patch.object(manager, '_update',
mock.Mock(return_value='fake_update')):
manager.update(
class_name, shares=1, snapshots=2, gigabytes=3,
snapshot_gigabytes=4, share_networks=5)
manager._update.assert_called_once_with(
expected_url, expected_body)

View File

@ -13,83 +13,143 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
cs = fakes.FakeClient()
from manilaclient.v2 import quotas
@ddt.ddt
class QuotaSetsTest(utils.TestCase):
def test_tenant_quotas_get(self):
tenant_id = 'test'
cs.quotas.get(tenant_id)
cs.assert_called('GET', '/os-quota-sets/%s' % tenant_id)
def _get_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return quotas.QuotaSetManager(api=mock_microversion)
def test_user_quotas_get(self):
def _get_resource_path(self, microversion):
if float(microversion) > 2.6:
return quotas.RESOURCE_PATH
return quotas.RESOURCE_PATH_LEGACY
@ddt.data("2.6", "2.7")
def test_tenant_quotas_get(self, microversion):
tenant_id = 'test'
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test" % resource_path
with mock.patch.object(manager, '_get',
mock.Mock(return_value='fake_get')):
manager.get(tenant_id)
manager._get.assert_called_once_with(expected_url, "quota_set")
@ddt.data("2.6", "2.7")
def test_user_quotas_get(self, microversion):
tenant_id = 'test'
user_id = 'fake_user'
cs.quotas.get(tenant_id, user_id=user_id)
url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
cs.assert_called('GET', url)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test?user_id=fake_user" % resource_path
with mock.patch.object(manager, '_get',
mock.Mock(return_value='fake_get')):
manager.get(tenant_id, user_id=user_id)
def test_tenant_quotas_defaults(self):
manager._get.assert_called_once_with(expected_url, "quota_set")
@ddt.data("2.6", "2.7")
def test_tenant_quotas_defaults(self, microversion):
tenant_id = 'test'
cs.quotas.defaults(tenant_id)
cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test/defaults" % resource_path
with mock.patch.object(manager, '_get',
mock.Mock(return_value='fake_get')):
manager.defaults(tenant_id)
def test_update_quota(self):
q = cs.quotas.get('test')
q.update(shares=1)
q.update(snapshots=2)
q.update(gigabytes=3)
q.update(snapshot_gigabytes=4)
q.update(share_networks=5)
cs.assert_called('PUT', '/os-quota-sets/test')
manager._get.assert_called_once_with(expected_url, "quota_set")
def test_update_user_quota(self):
@ddt.data(
("2.6", {}),
("2.6", {"force": True}),
("2.7", {}),
("2.7", {"force": True}),
)
@ddt.unpack
def test_update_quota(self, microversion, extra_data):
tenant_id = 'test'
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test" % resource_path
expected_body = {
'quota_set': {
'tenant_id': tenant_id,
'shares': 1,
'snapshots': 2,
'gigabytes': 3,
'snapshot_gigabytes': 4,
'share_networks': 5,
},
}
expected_body['quota_set'].update(extra_data)
with mock.patch.object(manager, '_update',
mock.Mock(return_value='fake_update')):
manager.update(
tenant_id, shares=1, snapshots=2, gigabytes=3,
snapshot_gigabytes=4, share_networks=5, **extra_data)
manager._update.assert_called_once_with(
expected_url, expected_body, "quota_set")
@ddt.data("2.6", "2.7")
def test_update_user_quota(self, microversion):
tenant_id = 'test'
user_id = 'fake_user'
q = cs.quotas.get(tenant_id)
q.update(shares=1, user_id=user_id)
q.update(snapshots=2, user_id=user_id)
q.update(gigabytes=3, user_id=user_id)
q.update(snapshot_gigabytes=4, user_id=user_id)
q.update(share_networks=5, user_id=user_id)
url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
cs.assert_called('PUT', url)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test?user_id=fake_user" % resource_path
expected_body = {
'quota_set': {
'tenant_id': tenant_id,
'shares': 1,
'snapshots': 2,
'gigabytes': 3,
'snapshot_gigabytes': 4,
'share_networks': 5,
},
}
with mock.patch.object(manager, '_update',
mock.Mock(return_value='fake_update')):
manager.update(
tenant_id, shares=1, snapshots=2, gigabytes=3,
snapshot_gigabytes=4, share_networks=5, user_id=user_id)
def test_force_update_quota(self):
q = cs.quotas.get('test')
q.update(shares=2, force=True)
cs.assert_called(
'PUT', '/os-quota-sets/test',
{'quota_set': {'force': True,
'shares': 2,
'tenant_id': 'test'}})
manager._update.assert_called_once_with(
expected_url, expected_body, "quota_set")
def test_quotas_delete(self):
@ddt.data("2.6", "2.7")
def test_quotas_delete(self, microversion):
tenant_id = 'test'
cs.quotas.delete(tenant_id)
cs.assert_called('DELETE', '/os-quota-sets/%s' % tenant_id)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test" % resource_path
with mock.patch.object(manager, '_delete',
mock.Mock(return_value='fake_delete')):
manager.delete(tenant_id)
def test_user_quotas_delete(self):
manager._delete.assert_called_once_with(expected_url)
@ddt.data("2.6", "2.7")
def test_user_quotas_delete(self, microversion):
tenant_id = 'test'
user_id = 'fake_user'
cs.quotas.delete(tenant_id, user_id=user_id)
url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
cs.assert_called('DELETE', url)
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
expected_url = "%s/test?user_id=fake_user" % resource_path
with mock.patch.object(manager, '_delete',
mock.Mock(return_value='fake_delete')):
manager.delete(tenant_id, user_id=user_id)
def test_refresh_quota(self):
q = cs.quotas.get('test')
q2 = cs.quotas.get('test')
self.assertEqual(q.shares, q2.shares)
self.assertEqual(q.snapshots, q2.snapshots)
q2.shares = 0
self.assertNotEqual(q.shares, q2.shares)
q2.snapshots = 0
self.assertNotEqual(q.snapshots, q2.snapshots)
q2.get()
self.assertEqual(q.shares, q2.shares)
self.assertEqual(q.snapshots, q2.snapshots)
manager._delete.assert_called_once_with(expected_url)

View File

@ -13,66 +13,86 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient.tests.unit import utils
from manilaclient.v2 import services
@ddt.ddt
class ServicesTest(utils.TestCase):
def setUp(self):
super(ServicesTest, self).setUp()
self.manager = services.ServiceManager(api=None)
def _get_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return services.ServiceManager(api=mock_microversion)
def test_list(self):
with mock.patch.object(self.manager, '_list',
mock.Mock(return_value=None)):
self.manager.list()
self.manager._list.assert_called_once_with(
services.RESOURCES_PATH,
services.RESOURCES_NAME,
)
def _get_resource_path(self, microversion):
if float(microversion) > 2.6:
return services.RESOURCE_PATH
return services.RESOURCE_PATH_LEGACY
@ddt.data("2.6", "2.7")
def test_list(self, microversion):
manager = self._get_manager(microversion)
resource_path = self._get_resource_path(microversion)
with mock.patch.object(manager, '_list',
mock.Mock(return_value='fake')):
result = manager.list()
manager._list.assert_called_once_with(
resource_path, services.RESOURCE_NAME)
self.assertEqual("fake", result)
def test_list_services_with_one_search_opt(self):
manager = self._get_manager("2.7")
host = 'fake_host'
query_string = "?host=%s" % host
with mock.patch.object(self.manager, '_list',
with mock.patch.object(manager, '_list',
mock.Mock(return_value=None)):
self.manager.list({'host': host})
self.manager._list.assert_called_once_with(
services.RESOURCES_PATH + query_string,
services.RESOURCES_NAME,
manager.list({'host': host})
manager._list.assert_called_once_with(
services.RESOURCE_PATH + query_string,
services.RESOURCE_NAME,
)
def test_list_services_with_two_search_opts(self):
manager = self._get_manager("2.7")
host = 'fake_host'
binary = 'fake_binary'
query_string = "?binary=%s&host=%s" % (binary, host)
with mock.patch.object(self.manager, '_list',
with mock.patch.object(manager, '_list',
mock.Mock(return_value=None)):
self.manager.list({'binary': binary, 'host': host})
self.manager._list.assert_called_once_with(
services.RESOURCES_PATH + query_string,
services.RESOURCES_NAME,
manager.list({'binary': binary, 'host': host})
manager._list.assert_called_once_with(
services.RESOURCE_PATH + query_string,
services.RESOURCE_NAME,
)
def test_enable_service(self):
@ddt.data("2.6", "2.7")
def test_enable_service(self, microversion):
manager = self._get_manager(microversion)
host = 'fake_host'
binary = 'fake_binary'
with mock.patch.object(self.manager, '_update'):
self.manager.enable(binary=binary, host=host)
self.manager._update.assert_called_once_with(
services.RESOURCES_PATH + '/enable',
with mock.patch.object(manager, '_update'):
manager.enable(binary=binary, host=host)
manager._update.assert_called_once_with(
self._get_resource_path(microversion) + '/enable',
{"host": host, "binary": binary},
)
def test_disable_service(self):
@ddt.data("2.6", "2.7")
def test_disable_service(self, microversion):
manager = self._get_manager(microversion)
host = 'fake_host'
binary = 'fake_binary'
with mock.patch.object(self.manager, '_update'):
self.manager.disable(binary=binary, host=host)
self.manager._update.assert_called_once_with(
services.RESOURCES_PATH + '/disable',
with mock.patch.object(manager, '_update'):
manager.disable(binary=binary, host=host)
manager._update.assert_called_once_with(
self._get_resource_path(microversion) + '/disable',
{"host": host, "binary": binary},
)

View File

@ -14,7 +14,9 @@
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient import extension
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
@ -30,6 +32,11 @@ cs = fakes.FakeClient(extensions=extensions)
@ddt.ddt
class ShareInstancesTest(utils.TestCase):
def _get_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return share_instances.ShareInstanceManager(api=mock_microversion)
def test_list(self):
cs.share_instances.list()
cs.assert_called('GET', '/share_instances')
@ -39,15 +46,44 @@ class ShareInstancesTest(utils.TestCase):
cs.share_instances.get(instance)
cs.assert_called('GET', '/share_instances/1234')
def test_force_delete(self):
instance = cs.share_instances.get('1234')
cs.share_instances.force_delete(instance)
cs.assert_called('POST', '/share_instances/1234/action',
{'os-force_delete': None})
def test_reset_state(self):
@ddt.data(
("2.6", type("InstanceUUID", (object, ), {"uuid": "1234"})),
("2.7", type("InstanceUUID", (object, ), {"uuid": "1234"})),
("2.6", type("InstanceID", (object, ), {"id": "1234"})),
("2.7", type("InstanceID", (object, ), {"id": "1234"})),
("2.6", "1234"),
("2.7", "1234"),
)
@ddt.unpack
def test_reset_instance_state(self, microversion, instance):
manager = self._get_manager(microversion)
state = 'available'
expected_body = {'os-reset_status': {'status': 'available'}}
instance = cs.share_instances.get('1234')
cs.share_instances.reset_state(instance, state)
cs.assert_called('POST', '/share_instances/1234/action', expected_body)
if float(microversion) > 2.6:
action_name = "reset_status"
else:
action_name = "os-reset_status"
with mock.patch.object(manager, "_action", mock.Mock()):
manager.reset_state(instance, state)
manager._action.assert_called_once_with(
action_name, instance, {"status": state})
@ddt.data(
("2.6", type('InstanceUUID', (object, ), {"uuid": "1234"})),
("2.6", "1234"),
("2.7", type('InstanceUUID', (object, ), {"uuid": "1234"})),
("2.7", "1234"),
)
@ddt.unpack
def test_force_delete_share_snapshot(self, microversion, instance):
manager = self._get_manager(microversion)
if float(microversion) > 2.6:
action_name = "force_delete"
else:
action_name = "os-force_delete"
with mock.patch.object(manager, "_action", mock.Mock()):
manager.force_delete(instance)
manager._action.assert_called_once_with(action_name, "1234")

View File

@ -16,7 +16,9 @@
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient import extension
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
@ -32,6 +34,11 @@ cs = fakes.FakeClient(extensions=extensions)
@ddt.ddt
class ShareSnapshotsTest(utils.TestCase):
def _get_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return share_snapshots.ShareSnapshotManager(api=mock_microversion)
def test_create_share_snapshot(self):
cs.share_snapshots.create(1234)
cs.assert_called('POST', '/snapshots')
@ -54,25 +61,51 @@ class ShareSnapshotsTest(utils.TestCase):
cs.assert_called('PUT', '/snapshots/1234', {'snapshot': data})
@ddt.data(
type('SnapshotUUID', (object, ), {'uuid': '1234'}),
type('SnapshotID', (object, ), {'id': '1234'}),
'1234')
def test_reset_snapshot_state(self, snapshot):
("2.6", type('SnapshotUUID', (object, ), {'uuid': '1234'})),
("2.7", type('SnapshotUUID', (object, ), {'uuid': '1234'})),
("2.6", type('SnapshotID', (object, ), {'id': '1234'})),
("2.7", type('SnapshotID', (object, ), {'id': '1234'})),
("2.6", "1234"),
("2.7", "1234"),
)
@ddt.unpack
def test_reset_snapshot_state(self, microversion, snapshot):
manager = self._get_manager(microversion)
state = 'available'
expected_body = {'os-reset_status': {'status': 'available'}}
cs.share_snapshots.reset_state(snapshot, state)
cs.assert_called('POST', '/snapshots/1234/action', expected_body)
if float(microversion) > 2.6:
action_name = "reset_status"
else:
action_name = "os-reset_status"
with mock.patch.object(manager, "_action", mock.Mock()):
manager.reset_state(snapshot, state)
manager._action.assert_called_once_with(
action_name, snapshot, {"status": state})
def test_delete_share_snapshot(self):
snapshot = cs.share_snapshots.get(1234)
cs.share_snapshots.delete(snapshot)
cs.assert_called('DELETE', '/snapshots/1234')
def test_force_delete_share_snapshot(self):
snapshot = cs.share_snapshots.get(1234)
cs.share_snapshots.force_delete(snapshot)
cs.assert_called('POST', '/snapshots/1234/action',
{'os-force_delete': None})
@ddt.data(
("2.6", type('SnapshotUUID', (object, ), {"uuid": "1234"})),
("2.6", "1234"),
("2.7", type('SnapshotUUID', (object, ), {"uuid": "1234"})),
("2.7", "1234"),
)
@ddt.unpack
def test_force_delete_share_snapshot(self, microversion, snapshot):
manager = self._get_manager(microversion)
if float(microversion) > 2.6:
action_name = "force_delete"
else:
action_name = "os-force_delete"
with mock.patch.object(manager, "_action", mock.Mock()):
manager.force_delete(snapshot)
manager._action.assert_called_once_with(action_name, "1234")
def test_list_share_snapshots_index(self):
cs.share_snapshots.list(detailed=False)

View File

@ -18,13 +18,13 @@
import ddt
import mock
from manilaclient import api_versions
from manilaclient import exceptions
from manilaclient import extension
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
from manilaclient.v2 import shares
extensions = [
extension.Extension('shares', shares),
]
@ -206,20 +206,92 @@ class SharesTest(utils.TestCase):
cs.shares.delete(share)
cs.assert_called('DELETE', '/shares/1234')
def test_manage_share(self):
cs.shares.manage('fake_service', 'fake_proto', 'fake_export_path', {})
cs.assert_called('POST', '/os-share-manage')
@ddt.data(
("2.6", "/os-share-manage"),
("2.7", "/shares/manage"),
)
@ddt.unpack
def test_manage_share(self, microversion, resource_path):
service_host = "fake_service_host"
protocol = "fake_protocol"
export_path = "fake_export_path"
driver_options = "fake_driver_options"
share_type = "fake_share_type"
name = "foo_name"
description = "bar_description"
expected_body = {
"service_host": service_host,
"share_type": share_type,
"protocol": protocol,
"export_path": export_path,
"driver_options": driver_options,
"name": name,
"description": description,
}
def test_unmanage_share(self):
share = cs.shares.get('1234')
cs.shares.unmanage(share)
cs.assert_called('POST', '/os-share-unmanage/1234/unmanage')
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
def test_force_delete_share(self):
share = cs.shares.get('1234')
cs.shares.force_delete(share)
cs.assert_called('POST', '/shares/1234/action',
{'os-force_delete': None})
with mock.patch.object(manager, "_create",
mock.Mock(return_value="fake")):
result = manager.manage(
service_host, protocol, export_path, driver_options,
share_type, name, description)
self.assertEqual(manager._create.return_value, result)
manager._create.assert_called_once_with(
resource_path, {"share": expected_body}, "share")
@ddt.data(
type("ShareUUID", (object, ), {"uuid": "1234"}),
type("ShareID", (object, ), {"id": "1234"}),
"1234")
def test_unmanage_share_v2_6(self, share):
version = api_versions.APIVersion("2.6")
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.unmanage(share)
self.assertFalse(manager._action.called)
self.assertNotEqual("fake", result)
self.assertEqual(manager.api.client.post.return_value, result)
manager.api.client.post.assert_called_once_with(
"/os-share-unmanage/1234/unmanage")
def test_unmanage_share_v2_7(self):
share = "fake_share"
version = api_versions.APIVersion("2.7")
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.unmanage(share)
manager._action.assert_called_once_with("unmanage", share)
self.assertEqual("fake", result)
@ddt.data(
("2.6", "os-force_delete"),
("2.7", "force_delete"),
)
@ddt.unpack
def test_force_delete_share(self, microversion, action_name):
share = "fake_share"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.force_delete(share)
manager._action.assert_called_once_with(action_name, share)
self.assertEqual("fake", result)
def test_list_shares_index(self):
cs.shares.list(detailed=False)
@ -279,17 +351,50 @@ class SharesTest(utils.TestCase):
def test_list_shares_by_improper_key(self):
self.assertRaises(ValueError, cs.shares.list, sort_key='fake')
def test_allow_access_to_share(self):
share = cs.shares.get(1234)
ip = '192.168.0.1'
cs.shares.allow(share, 'ip', ip, None)
cs.assert_called('POST', '/shares/1234/action')
@ddt.data(
("2.6", "os-allow_access"),
("2.7", "allow_access"),
)
@ddt.unpack
def test_allow_access_to_share(self, microversion, action_name):
access_level = "fake_access_level"
access_to = "fake_access_to"
access_type = "fake_access_type"
share = "fake_share"
access = ("foo", {"access": "bar"})
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
def test_allow_access_to_share_with_cert(self):
share = cs.shares.get(1234)
common_name = 'test.example.com'
cs.shares.allow(share, 'cert', common_name, None)
cs.assert_called('POST', '/shares/1234/action')
with mock.patch.object(manager, "_action",
mock.Mock(return_value=access)):
result = manager.allow(share, access_type, access_to, access_level)
manager._action.assert_called_once_with(
action_name, share, {"access_level": access_level,
"access_type": access_type,
"access_to": access_to})
self.assertEqual("bar", result)
@ddt.data(
("2.6", "os-deny_access"),
("2.7", "deny_access"),
)
@ddt.unpack
def test_deny_access_to_share(self, microversion, action_name):
access_id = "fake_access_id"
share = "fake_share"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.deny(share, access_id)
manager._action.assert_called_once_with(
action_name, share, {"access_id": access_id})
self.assertEqual("fake", result)
def test_get_metadata(self):
cs.shares.get_metadata(1234)
@ -319,41 +424,88 @@ class SharesTest(utils.TestCase):
{'metadata': {'k1': 'v1'}})
@ddt.data(
type('ShareUUID', (object, ), {'uuid': '1234'}),
type('ShareID', (object, ), {'id': '1234'}),
'1234')
def test_reset_share_state(self, share):
state = 'available'
expected_body = {'os-reset_status': {'status': 'available'}}
cs.shares.reset_state(share, state)
cs.assert_called('POST', '/shares/1234/action', expected_body)
("2.6", "os-reset_status"),
("2.7", "reset_status"),
)
@ddt.unpack
def test_reset_share_state(self, microversion, action_name):
state = "available"
share = "fake_share"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.reset_state(share, state)
manager._action.assert_called_once_with(
action_name, share, {"status": state})
self.assertEqual("fake", result)
@ddt.data(
type('ShareUUID', (object, ), {'uuid': '1234'}),
type('ShareID', (object, ), {'id': '1234'}),
'1234')
def test_extend_share(self, share):
("2.6", "os-extend"),
("2.7", "extend"),
)
@ddt.unpack
def test_extend_share(self, microversion, action_name):
size = 123
expected_body = {'os-extend': {'new_size': size}}
cs.shares.extend(share, size)
cs.assert_called('POST', '/shares/1234/action', expected_body)
share = "fake_share"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.extend(share, size)
manager._action.assert_called_once_with(
action_name, share, {"new_size": size})
self.assertEqual("fake", result)
@ddt.data(
type('ShareUUID', (object, ), {'uuid': '1234'}),
type('ShareID', (object, ), {'id': '1234'}),
'1234')
def test_shrink_share(self, share):
("2.6", "os-shrink"),
("2.7", "shrink"),
)
@ddt.unpack
def test_shrink_share(self, microversion, action_name):
size = 123
expected_body = {'os-shrink': {'new_size': size}}
cs.shares.shrink(share, size)
cs.assert_called('POST', '/shares/1234/action', expected_body)
share = "fake_share"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.shrink(share, size)
manager._action.assert_called_once_with(
action_name, share, {"new_size": size})
self.assertEqual("fake", result)
def test_list_share_instances(self):
share = type('ShareID', (object, ), {'id': '1234'})
cs.shares.list_instances(share)
cs.assert_called('GET', '/shares/1234/instances')
def test_migrate_share(self):
host = 'fake_host'
self.share.migrate_share(host, True)
self.assertTrue(self.share.manager.migrate_share.called)
@ddt.data(
("2.6", "os-migrate_share"),
("2.7", "migrate_share"),
)
@ddt.unpack
def test_migrate_share(self, microversion, action_name):
share = "fake_share"
host = "fake_host"
force_host_copy = "fake_force_host_copy"
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
manager = shares.ShareManager(api=mock_microversion)
with mock.patch.object(manager, "_action",
mock.Mock(return_value="fake")):
result = manager.migrate_share(share, host, force_host_copy)
manager._action.assert_called_once_with(
action_name, share,
{"host": host, "force_host_copy": force_host_copy})
self.assertEqual("fake", result)

View File

@ -101,20 +101,20 @@ class ShellTest(test_utils.TestCase):
def test_service_list(self):
self.run_command('service-list')
self.assert_called('GET', '/os-services')
self.assert_called('GET', '/services')
def test_service_enable(self):
self.run_command('service-enable foo_host@bar_backend manila-share')
self.assert_called(
'PUT',
'/os-services/enable',
'/services/enable',
{'host': 'foo_host@bar_backend', 'binary': 'manila-share'})
def test_service_disable(self):
self.run_command('service-disable foo_host@bar_backend manila-share')
self.assert_called(
'PUT',
'/os-services/disable',
'/services/disable',
{'host': 'foo_host@bar_backend', 'binary': 'manila-share'})
def test_list(self):
@ -315,7 +315,7 @@ class ShellTest(test_utils.TestCase):
def test_share_instance_reset_state(self):
self.run_command('share-instance-reset-state 1234')
expected = {'os-reset_status': {'status': 'available'}}
expected = {'reset_status': {'status': 'available'}}
self.assert_called('POST', '/share_instances/1234/action',
body=expected)
@ -357,7 +357,7 @@ class ShellTest(test_utils.TestCase):
'driver_handles_share_servers': False,
'snapshot_support': True,
},
'os-share-type-access:is_public': public
'share_type_access:is_public': public
}
}
self.run_command(
@ -367,7 +367,7 @@ class ShellTest(test_utils.TestCase):
def test_type_access_list(self):
self.run_command('type-access-list 3')
self.assert_called('GET', '/types/3/os-share-type-access')
self.assert_called('GET', '/types/3/share_type_access')
def test_type_access_add_project(self):
expected = {'addProjectAccess': {'project': '101'}}
@ -438,11 +438,11 @@ class ShellTest(test_utils.TestCase):
}
expected['share'].update(valid_params)
self.assert_called('POST', '/os-share-manage', body=expected)
self.assert_called('POST', '/shares/manage', body=expected)
def test_unmanage(self):
self.run_command('unmanage 1234')
self.assert_called('POST', '/os-share-unmanage/1234/unmanage')
self.assert_called('POST', '/shares/1234/action')
def test_delete(self):
self.run_command('delete 1234')
@ -595,7 +595,7 @@ class ShellTest(test_utils.TestCase):
expected = {
"share_type": {
"name": "test",
"os-share-type-access:is_public": True,
"share_type_access:is_public": True,
"extra_specs": {
"driver_handles_share_servers": expected_bool,
"snapshot_support": True,
@ -618,7 +618,7 @@ class ShellTest(test_utils.TestCase):
expected = {
"share_type": {
"name": "test",
"os-share-type-access:is_public": True,
"share_type_access:is_public": True,
"extra_specs": {
"driver_handles_share_servers": False,
"snapshot_support": expected_bool,
@ -743,32 +743,32 @@ class ShellTest(test_utils.TestCase):
def test_extend(self):
self.run_command('extend 1234 77')
expected = {'os-extend': {'new_size': 77}}
expected = {'extend': {'new_size': 77}}
self.assert_called('POST', '/shares/1234/action', body=expected)
def test_reset_state(self):
self.run_command('reset-state 1234')
expected = {'os-reset_status': {'status': 'available'}}
expected = {'reset_status': {'status': 'available'}}
self.assert_called('POST', '/shares/1234/action', body=expected)
def test_shrink(self):
self.run_command('shrink 1234 77')
expected = {'os-shrink': {'new_size': 77}}
expected = {'shrink': {'new_size': 77}}
self.assert_called('POST', '/shares/1234/action', body=expected)
def test_reset_state_with_flag(self):
self.run_command('reset-state --state error 1234')
expected = {'os-reset_status': {'status': 'error'}}
expected = {'reset_status': {'status': 'error'}}
self.assert_called('POST', '/shares/1234/action', body=expected)
def test_snapshot_reset_state(self):
self.run_command('snapshot-reset-state 1234')
expected = {'os-reset_status': {'status': 'available'}}
expected = {'reset_status': {'status': 'available'}}
self.assert_called('POST', '/snapshots/1234/action', body=expected)
def test_snapshot_reset_state_with_flag(self):
self.run_command('snapshot-reset-state --state error 1234')
expected = {'os-reset_status': {'status': 'error'}}
expected = {'reset_status': {'status': 'error'}}
self.assert_called('POST', '/snapshots/1234/action', body=expected)
@ddt.data(
@ -1088,7 +1088,7 @@ class ShellTest(test_utils.TestCase):
self.run_command("access-allow 1234 cert client.example.com")
expected = {
"os-allow_access": {
"allow_access": {
"access_type": "cert",
"access_to": "client.example.com",
}
@ -1121,7 +1121,7 @@ class ShellTest(test_utils.TestCase):
def test_allow_access_with_access_level(self):
aliases = ['--access_level', '--access-level']
expected = {
"os-allow_access": {
"allow_access": {
"access_type": "ip",
"access_to": "10.0.0.6",
"access_level": "ro",
@ -1137,14 +1137,14 @@ class ShellTest(test_utils.TestCase):
def test_allow_access_with_valid_access_levels(self):
expected = {
"os-allow_access": {
"allow_access": {
"access_type": "ip",
"access_to": "10.0.0.6",
}
}
for level in ['rw', 'ro']:
expected["os-allow_access"]['access_level'] = level
expected["allow_access"]['access_level'] = level
self.run_command(
"access-allow --access-level " + level + " 1111 ip 10.0.0.6")
self.assert_called("POST", "/shares/1111/action",
@ -1359,7 +1359,7 @@ class ShellTest(test_utils.TestCase):
self.run_command('cg-delete --force fake-cg')
self.assert_called('POST', '/consistency-groups/1234/action',
{'os-force_delete': None})
{'force_delete': None})
@mock.patch.object(shell_v2, '_find_consistency_group', mock.Mock())
def test_cg_reset_state_with_flag(self):
@ -1368,7 +1368,7 @@ class ShellTest(test_utils.TestCase):
self.run_command('cg-reset-state --state error 1234')
self.assert_called('POST', '/consistency-groups/1234/action',
{'os-reset_status': {'status': 'error'}})
{'reset_status': {'status': 'error'}})
@mock.patch.object(shell_v2, '_find_cg_snapshot', mock.Mock())
def test_cg_snapshot_reset_state(self):
@ -1377,7 +1377,7 @@ class ShellTest(test_utils.TestCase):
self.run_command('cg-snapshot-reset-state 1234')
self.assert_called('POST', '/cgsnapshots/1234/action',
{'os-reset_status': {'status': 'available'}})
{'reset_status': {'status': 'available'}})
@mock.patch.object(shell_v2, '_find_cg_snapshot', mock.Mock())
def test_cg_snapshot_reset_state_with_flag(self):
@ -1386,7 +1386,7 @@ class ShellTest(test_utils.TestCase):
self.run_command('cg-snapshot-reset-state --state creating 1234')
self.assert_called('POST', '/cgsnapshots/1234/action',
{'os-reset_status': {'status': 'creating'}})
{'reset_status': {'status': 'creating'}})
@mock.patch.object(cliutils, 'print_list', mock.Mock())
def test_cg_snapshot_list(self):
@ -1456,7 +1456,7 @@ class ShellTest(test_utils.TestCase):
self.run_command('cg-snapshot-delete --force fake-cg')
self.assert_called('POST', '/cgsnapshots/1234/action',
{'os-force_delete': None})
{'force_delete': None})
@ddt.data(
{'--shares': 5},
@ -1481,4 +1481,4 @@ class ShellTest(test_utils.TestCase):
expected = dict(quota_class_set=expected)
self.run_command(cmd)
self.assert_called('PUT', '/os-quota-class-sets/test', body=expected)
self.assert_called('PUT', '/quota-class-sets/test', body=expected)

View File

@ -1,5 +1,5 @@
# Copyright (c) 2013 OpenStack Foundation
#
# Copyright (c) 2015 Mirantis, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,41 +14,81 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from manilaclient import api_versions
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
from manilaclient.v2 import share_type_access
cs = fakes.FakeClient()
PROJECT_UUID = '11111111-1111-1111-111111111111'
@ddt.ddt
class TypeAccessTest(utils.TestCase):
def test_list(self):
def _get_share_type_access_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return share_type_access.ShareTypeAccessManager(
api=mock_microversion)
@ddt.data(
("1.0", "os-share-type-access"),
("2.0", "os-share-type-access"),
("2.6", "os-share-type-access"),
("2.7", "share_type_access"),
)
@ddt.unpack
def test_list(self, microversion, action_name):
fake_access_list = ['foo', 'bar']
share_type = mock.Mock()
share_type.uuid = '3'
share_type.is_public = False
access = cs.share_type_access.list(share_type=share_type)
cs.assert_called('GET', '/types/3/os-share-type-access')
for a in access:
self.assertTrue(isinstance(a, share_type_access.ShareTypeAccess))
manager = self._get_share_type_access_manager(microversion)
def test_list_public(self):
with mock.patch.object(manager, '_list',
mock.Mock(return_value=fake_access_list)):
access = manager.list(share_type=share_type)
manager._list.assert_called_once_with(
"/types/3/%s" % action_name, "share_type_access")
self.assertEqual(fake_access_list, access)
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_list_public(self, microversion):
share_type = mock.Mock()
share_type.uuid = '4'
share_type.is_public = True
actual_result = cs.share_type_access.list(share_type=share_type)
self.assertEqual(None, actual_result)
manager = self._get_share_type_access_manager(microversion)
def test_add_project_access(self):
cs.share_type_access.add_project_access('3', PROJECT_UUID)
cs.assert_called('POST', '/types/3/action',
{'addProjectAccess': {'project': PROJECT_UUID}})
with mock.patch.object(manager, '_list',
mock.Mock(return_value='fake')):
access = manager.list(share_type=share_type)
def test_remove_project_access(self):
cs.share_type_access.remove_project_access('3', PROJECT_UUID)
cs.assert_called('POST', '/types/3/action',
{'removeProjectAccess': {'project': PROJECT_UUID}})
self.assertFalse(manager._list.called)
self.assertEqual(None, access)
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_add_project_access(self, microversion):
share_type = mock.Mock()
manager = self._get_share_type_access_manager(microversion)
with mock.patch.object(manager, '_action',
mock.Mock(return_value='fake_action')):
manager.add_project_access(share_type, PROJECT_UUID)
manager._action.assert_called_once_with(
'addProjectAccess', share_type, {'project': PROJECT_UUID})
@ddt.data("1.0", "2.0", "2.6", "2.7")
def test_remove_project_access(self, microversion):
share_type = mock.Mock()
manager = self._get_share_type_access_manager(microversion)
with mock.patch.object(manager, '_action',
mock.Mock(return_value='fake_action')):
manager.remove_project_access(share_type, PROJECT_UUID)
manager._action.assert_called_once_with(
'removeProjectAccess', share_type, {'project': PROJECT_UUID})

View File

@ -14,6 +14,7 @@
import ddt
import mock
from manilaclient import api_versions
from manilaclient.tests.unit import utils
from manilaclient.tests.unit.v2 import fakes
from manilaclient.v2 import share_types
@ -24,6 +25,11 @@ cs = fakes.FakeClient()
@ddt.ddt
class TypesTest(utils.TestCase):
def _get_share_types_manager(self, microversion):
version = api_versions.APIVersion(microversion)
mock_microversion = mock.Mock(api_version=version)
return share_types.ShareTypeManager(api=mock_microversion)
@ddt.data(
{'snapshot_support': 'False'},
{'snapshot_support': 'False', 'foo': 'bar'},
@ -67,10 +73,11 @@ class TypesTest(utils.TestCase):
)
@ddt.unpack
def test_create(self, is_public, dhss, snapshot_support):
manager = self._get_share_types_manager("2.7")
expected_body = {
"share_type": {
"name": 'test-type-3',
'os-share-type-access:is_public': is_public,
'share_type_access:is_public': is_public,
"extra_specs": {
"driver_handles_share_servers": dhss,
"snapshot_support": snapshot_support,
@ -78,17 +85,32 @@ class TypesTest(utils.TestCase):
}
}
result = cs.share_types.create(
'test-type-3', dhss, snapshot_support, is_public=is_public)
cs.assert_called('POST', '/types', expected_body)
self.assertIsInstance(result, share_types.ShareType)
with mock.patch.object(manager, '_create',
mock.Mock(return_value="fake")):
result = manager.create(
'test-type-3', dhss, snapshot_support, is_public=is_public)
@ddt.data(True, False)
def test_create_with_default_values(self, dhss):
manager._create.assert_called_once_with(
"/types", expected_body, "share_type")
self.assertEqual("fake", result)
@ddt.data(
("2.6", True),
("2.7", True),
("2.6", False),
("2.7", False),
)
@ddt.unpack
def test_create_with_default_values(self, microversion, dhss):
manager = self._get_share_types_manager(microversion)
if float(microversion) > 2.6:
is_public_keyname = "share_type_access:is_public"
else:
is_public_keyname = "os-share-type-access:is_public"
expected_body = {
"share_type": {
"name": 'test-type-3',
'os-share-type-access:is_public': True,
is_public_keyname: True,
"extra_specs": {
"driver_handles_share_servers": dhss,
"snapshot_support": True,
@ -96,9 +118,13 @@ class TypesTest(utils.TestCase):
}
}
result = cs.share_types.create('test-type-3', dhss)
cs.assert_called('POST', '/types', expected_body)
self.assertIsInstance(result, share_types.ShareType)
with mock.patch.object(manager, '_create',
mock.Mock(return_value="fake")):
result = manager.create('test-type-3', dhss)
manager._create.assert_called_once_with(
"/types", expected_body, "share_type")
self.assertEqual("fake", result)
def test_set_key(self):
t = cs.share_types.get(1)

View File

@ -123,8 +123,7 @@ class ConsistencyGroupSnapshotManager(base.ManagerWithFind):
return self._list(path, RESOURCES_NAME)
@api_versions.wraps("2.4")
def delete(self, cg_snapshot, force=False):
def _do_delete(self, cg_snapshot, force=False, action_name='force_delete'):
"""Delete a consistency group snapshot.
:param cg_snapshot: either a cg snapshot object or text wit its ID.
@ -133,13 +132,21 @@ class ConsistencyGroupSnapshotManager(base.ManagerWithFind):
body = None
if force:
body = {'os-force_delete': None}
body = {action_name: None}
if body:
self.api.client.post(RESOURCE_PATH_ACTION % cg_id, body=body)
else:
self._delete(RESOURCE_PATH % cg_id)
@api_versions.wraps("2.4", "2.6")
def delete(self, cg_snapshot, force=False):
return self._do_delete(cg_snapshot, force, 'os-force_delete')
@api_versions.wraps("2.7") # noqa
def delete(self, cg_snapshot, force=False):
return self._do_delete(cg_snapshot, force, 'force_delete')
@api_versions.wraps("2.4")
def members(self, cg_snapshot, search_opts=None):
"""Get a list of consistency group snapshot members.
@ -161,14 +168,21 @@ class ConsistencyGroupSnapshotManager(base.ManagerWithFind):
return self._list(path, MEMBERS_RESOURCE_NAME)
@api_versions.wraps("2.4")
def reset_state(self, cg_snapshot, state):
def _do_reset_state(self, cg_snapshot, state, action_name):
"""Update the specified consistency group with the provided state."""
body = {'os-reset_status': {'status': state}}
body = {action_name: {'status': state}}
cg_id = common_base.getid(cg_snapshot)
url = RESOURCE_PATH_ACTION % cg_id
return self.api.client.post(url, body=body)
@api_versions.wraps("2.4", "2.6")
def reset_state(self, cg_snapshot, state):
return self._do_reset_state(cg_snapshot, state, 'os-reset_status')
@api_versions.wraps("2.7") # noqa
def reset_state(self, cg_snapshot, state):
return self._do_reset_state(cg_snapshot, state, 'reset_status')
def _query_string_helper(self, search_opts):
q_string = parse.urlencode(
sorted([(k, v) for (k, v) in list(search_opts.items()) if v]))

View File

@ -139,8 +139,8 @@ class ConsistencyGroupManager(base.ManagerWithFind):
return self._list(path, RESOURCES_NAME)
@api_versions.wraps("2.4")
def delete(self, consistency_group, force=False):
def _do_delete(self, consistency_group, force=False,
action_name='force_delete'):
"""Delete a consistency group.
:param consistency_group: either consistency group object or text with
@ -151,20 +151,36 @@ class ConsistencyGroupManager(base.ManagerWithFind):
body = None
if force:
body = {'os-force_delete': None}
body = {action_name: None}
if body:
self.api.client.post(url + '/action', body=body)
else:
self._delete(url)
@api_versions.wraps("2.4")
def reset_state(self, consistency_group, state):
@api_versions.wraps("2.4", "2.6")
def delete(self, consistency_group, force=False):
return self._do_delete(consistency_group, force, 'os-force_delete')
@api_versions.wraps("2.7") # noqa
def delete(self, consistency_group, force=False):
return self._do_delete(consistency_group, force, 'force_delete')
def _do_reset_state(self, consistency_group, state, action_name):
"""Update the specified consistency group with the provided state."""
body = {'os-reset_status': {'status': state}}
body = {action_name: {'status': state}}
url = RESOURCE_PATH_ACTION % common_base.getid(consistency_group)
return self.api.client.post(url, body=body)
@api_versions.wraps("2.4", "2.6")
def reset_state(self, cg, state):
return self._do_reset_state(
consistency_group, state, 'os-reset_status')
@api_versions.wraps("2.7") # noqa
def reset_state(self, consistency_group, state):
return self._do_reset_state(consistency_group, state, 'reset_status')
def _query_string_helper(self, search_opts):
q_string = parse.urlencode(
sorted([(k, v) for (k, v) in list(search_opts.items()) if v]))

View File

@ -13,9 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
RESOURCE_PATH_LEGACY = '/os-quota-class-sets'
RESOURCE_PATH = '/quota-class-sets'
class QuotaClassSet(common_base.Resource):
@ -31,18 +35,24 @@ class QuotaClassSet(common_base.Resource):
class QuotaClassSetManager(base.ManagerWithFind):
resource_class = QuotaClassSet
@api_versions.wraps("1.0", "2.6")
def get(self, class_name):
return self._get("/os-quota-class-sets/%s" % class_name,
"quota_class_set")
return self._get(
"%(resource_path)s/%(class_name)s" % {
"resource_path": RESOURCE_PATH_LEGACY,
"class_name": class_name},
"quota_class_set")
def update(self,
class_name,
shares=None,
gigabytes=None,
snapshots=None,
snapshot_gigabytes=None,
share_networks=None):
@api_versions.wraps("2.7") # noqa
def get(self, class_name):
return self._get(
"%(resource_path)s/%(class_name)s" % {
"resource_path": RESOURCE_PATH, "class_name": class_name},
"quota_class_set")
def _do_update(self, class_name, shares=None, gigabytes=None,
snapshots=None, snapshot_gigabytes=None,
share_networks=None, resource_path=RESOURCE_PATH):
body = {
'quota_class_set': {
'class_name': class_name,
@ -58,4 +68,22 @@ class QuotaClassSetManager(base.ManagerWithFind):
if body['quota_class_set'][key] is None:
body['quota_class_set'].pop(key)
self._update('/os-quota-class-sets/%s' % class_name, body)
self._update(
"%(resource_path)s/%(class_name)s" % {
"resource_path": resource_path,
"class_name": class_name},
body)
@api_versions.wraps("1.0", "2.6")
def update(self, class_name, shares=None, gigabytes=None,
snapshots=None, snapshot_gigabytes=None, share_networks=None):
return self._do_update(
class_name, shares, gigabytes, snapshots, snapshot_gigabytes,
share_networks, RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def update(self, class_name, shares=None, gigabytes=None,
snapshots=None, snapshot_gigabytes=None, share_networks=None):
return self._do_update(
class_name, shares, gigabytes, snapshots, snapshot_gigabytes,
share_networks, RESOURCE_PATH)

View File

@ -13,9 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
RESOURCE_PATH_LEGACY = '/os-quota-sets'
RESOURCE_PATH = '/quota-sets'
class QuotaSet(common_base.Resource):
@ -31,18 +35,32 @@ class QuotaSet(common_base.Resource):
class QuotaSetManager(base.ManagerWithFind):
resource_class = QuotaSet
def get(self, tenant_id, user_id=None):
def _do_get(self, tenant_id, user_id=None, resource_path=RESOURCE_PATH):
if hasattr(tenant_id, 'tenant_id'):
tenant_id = tenant_id.tenant_id
data = {
"resource_path": resource_path,
"tenant_id": tenant_id,
"user_id": user_id,
}
if user_id:
url = "/os-quota-sets/%s?user_id=%s" % (tenant_id, user_id)
url = "%(resource_path)s/%(tenant_id)s?user_id=%(user_id)s" % data
else:
url = "/os-quota-sets/%s" % tenant_id
url = "%(resource_path)s/%(tenant_id)s" % data
return self._get(url, "quota_set")
def update(self, tenant_id, shares=None, snapshots=None,
gigabytes=None, snapshot_gigabytes=None,
share_networks=None, force=None, user_id=None):
@api_versions.wraps("1.0", "2.6")
def get(self, tenant_id, user_id=None):
return self._do_get(tenant_id, user_id, RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def get(self, tenant_id, user_id=None):
return self._do_get(tenant_id, user_id, RESOURCE_PATH)
def _do_update(self, tenant_id, shares=None, snapshots=None,
gigabytes=None, snapshot_gigabytes=None,
share_networks=None, force=None, user_id=None,
resource_path=RESOURCE_PATH):
body = {
'quota_set': {
@ -59,20 +77,67 @@ class QuotaSetManager(base.ManagerWithFind):
for key in list(body['quota_set']):
if body['quota_set'][key] is None:
body['quota_set'].pop(key)
data = {
"resource_path": resource_path,
"tenant_id": tenant_id,
"user_id": user_id,
}
if user_id:
url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
url = '%(resource_path)s/%(tenant_id)s?user_id=%(user_id)s' % data
else:
url = '/os-quota-sets/%s' % tenant_id
url = "%(resource_path)s/%(tenant_id)s" % data
return self._update(url, body, 'quota_set')
def defaults(self, tenant_id):
return self._get('/os-quota-sets/%s/defaults' % tenant_id,
'quota_set')
@api_versions.wraps("1.0", "2.6")
def update(self, tenant_id, shares=None, snapshots=None, gigabytes=None,
snapshot_gigabytes=None, share_networks=None, force=None,
user_id=None):
return self._do_update(
tenant_id, shares, snapshots, gigabytes, snapshot_gigabytes,
share_networks, force, user_id, RESOURCE_PATH_LEGACY,
)
def delete(self, tenant_id, user_id=None):
@api_versions.wraps("2.7") # noqa
def update(self, tenant_id, shares=None, snapshots=None, gigabytes=None,
snapshot_gigabytes=None, share_networks=None, force=None,
user_id=None):
return self._do_update(
tenant_id, shares, snapshots, gigabytes, snapshot_gigabytes,
share_networks, force, user_id, RESOURCE_PATH,
)
@api_versions.wraps("1.0", "2.6")
def defaults(self, tenant_id):
return self._get(
"%(resource_path)s/%(tenant_id)s/defaults" % {
"resource_path": RESOURCE_PATH_LEGACY, "tenant_id": tenant_id},
"quota_set")
@api_versions.wraps("2.7") # noqa
def defaults(self, tenant_id):
return self._get(
"%(resource_path)s/%(tenant_id)s/defaults" % {
"resource_path": RESOURCE_PATH, "tenant_id": tenant_id},
"quota_set")
def _do_delete(self, tenant_id, user_id=None, resource_path=RESOURCE_PATH):
data = {
"resource_path": resource_path,
"tenant_id": tenant_id,
"user_id": user_id,
}
if user_id:
url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
url = '%(resource_path)s/%(tenant_id)s?user_id=%(user_id)s' % data
else:
url = '/os-quota-sets/%s' % tenant_id
url = '%(resource_path)s/%(tenant_id)s' % data
self._delete(url)
@api_versions.wraps("1.0", "2.6")
def delete(self, tenant_id, user_id=None):
return self._do_delete(
tenant_id, user_id, resource_path=RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def delete(self, tenant_id, user_id=None):
return self._do_delete(tenant_id, user_id, resource_path=RESOURCE_PATH)

View File

@ -19,11 +19,13 @@ try:
except ImportError:
from urllib.parse import urlencode # noqa
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
RESOURCES_PATH = '/os-services'
RESOURCES_NAME = 'services'
RESOURCE_PATH_LEGACY = '/os-services'
RESOURCE_PATH = '/services'
RESOURCE_NAME = 'services'
class Service(common_base.Resource):
@ -40,7 +42,7 @@ class ServiceManager(base.Manager):
"""Manage :class:`Service` resources."""
resource_class = Service
def list(self, search_opts=None):
def _do_list(self, search_opts=None, resource_path=RESOURCE_PATH):
"""Get a list of all services.
:rtype: list of :class:`Service`
@ -51,17 +53,43 @@ class ServiceManager(base.Manager):
sorted([(k, v) for (k, v) in six.iteritems(search_opts) if v]))
if query_string:
query_string = "?%s" % query_string
return self._list(RESOURCES_PATH + query_string, RESOURCES_NAME)
return self._list(resource_path + query_string, RESOURCE_NAME)
def enable(self, host, binary):
@api_versions.wraps("1.0", "2.6")
def list(self, search_opts=None):
return self._do_list(
search_opts=search_opts, resource_path=RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def list(self, search_opts=None):
return self._do_list(
search_opts=search_opts, resource_path=RESOURCE_PATH)
def _do_enable(self, host, binary, resource_path=RESOURCE_PATH):
"""Enable the service specified by hostname and binary."""
body = {"host": host, "binary": binary}
return self._update("/os-services/enable", body)
return self._update("%s/enable" % resource_path, body)
def disable(self, host, binary):
@api_versions.wraps("1.0", "2.6")
def enable(self, host, binary):
return self._do_enable(host, binary, RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def enable(self, host, binary):
return self._do_enable(host, binary, RESOURCE_PATH)
def _do_disable(self, host, binary, resource_path=RESOURCE_PATH):
"""Disable the service specified by hostname and binary."""
body = {"host": host, "binary": binary}
return self._update("/os-services/disable", body)
return self._update("%s/disable" % resource_path, body)
@api_versions.wraps("1.0", "2.6")
def disable(self, host, binary):
return self._do_disable(host, binary, RESOURCE_PATH_LEGACY)
@api_versions.wraps("2.7") # noqa
def disable(self, host, binary):
return self._do_disable(host, binary, RESOURCE_PATH)
def server_api_version(self, url_append=""):
"""Returns the API Version supported by the server.

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
@ -35,6 +36,7 @@ class ShareInstanceManager(base.ManagerWithFind):
"""Manage :class:`ShareInstances` resources."""
resource_class = ShareInstance
@api_versions.wraps("2.3")
def get(self, instance):
"""Get a share instance.
@ -44,6 +46,7 @@ class ShareInstanceManager(base.ManagerWithFind):
share_id = common_base.getid(instance)
return self._get("/share_instances/%s" % share_id, "share_instance")
@api_versions.wraps("2.3")
def list(self):
"""List all share instances."""
return self._list('/share_instances', 'share_instances')
@ -61,17 +64,33 @@ class ShareInstanceManager(base.ManagerWithFind):
url = '/share_instances/%s/action' % common_base.getid(instance)
return self.api.client.post(url, body=body)
def force_delete(self, instance):
def _do_force_delete(self, instance, action_name="force_delete"):
"""Delete a share instance forcibly - share status will be avoided.
:param instance: either share instance object or text with its ID.
"""
return self._action('os-force_delete', common_base.getid(instance))
return self._action(action_name, common_base.getid(instance))
def reset_state(self, instance, state):
@api_versions.wraps("2.3", "2.6")
def force_delete(self, instance):
return self._do_force_delete(instance, "os-force_delete")
@api_versions.wraps("2.7") # noqa
def force_delete(self, instance):
return self._do_force_delete(instance, "force_delete")
def _do_reset_state(self, instance, state, action_name):
"""Update the provided share instance with the provided state.
:param instance: either share object or text with its ID.
:param state: text with new state to set for share.
"""
return self._action('os-reset_status', instance, {'status': state})
return self._action(action_name, instance, {"status": state})
@api_versions.wraps("2.3", "2.6")
def reset_state(self, instance, state):
return self._do_reset_state(instance, state, "os-reset_status")
@api_versions.wraps("2.7") # noqa
def reset_state(self, instance, state):
return self._do_reset_state(instance, state, "reset_status")

View File

@ -19,6 +19,7 @@ try:
except ImportError:
from urllib.parse import urlencode # noqa
from manilaclient import api_versions
from manilaclient import base
from manilaclient.common import constants
from manilaclient.openstack.common.apiclient import base as common_base
@ -127,9 +128,17 @@ class ShareSnapshotManager(base.ManagerWithFind):
"""
self._delete("/snapshots/%s" % common_base.getid(snapshot))
def force_delete(self, snapshot):
def _do_force_delete(self, snapshot, action_name="force_delete"):
"""Delete the specified snapshot ignoring its current state."""
return self._action('os-force_delete', common_base.getid(snapshot))
return self._action(action_name, common_base.getid(snapshot))
@api_versions.wraps("1.0", "2.6")
def force_delete(self, snapshot):
return self._do_force_delete(snapshot, "os-force_delete")
@api_versions.wraps("2.7") # noqa
def force_delete(self, snapshot):
return self._do_force_delete(snapshot, "force_delete")
def update(self, snapshot, **kwargs):
"""Update a snapshot.
@ -145,9 +154,17 @@ class ShareSnapshotManager(base.ManagerWithFind):
snapshot_id = common_base.getid(snapshot)
return self._update("/snapshots/%s" % snapshot_id, body)
def reset_state(self, snapshot, state):
def _do_reset_state(self, snapshot, state, action_name="reset_status"):
"""Update the specified share snapshot with the provided state."""
return self._action('os-reset_status', snapshot, {'status': state})
return self._action(action_name, snapshot, {"status": state})
@api_versions.wraps("1.0", "2.6")
def reset_state(self, snapshot, state):
return self._do_reset_state(snapshot, state, "os-reset_status")
@api_versions.wraps("2.7") # noqa
def reset_state(self, snapshot, state):
return self._do_reset_state(snapshot, state, "reset_status")
def _action(self, action, snapshot, info=None, **kwargs):
"""Perform a snapshot 'action'."""

View File

@ -14,6 +14,7 @@
"""Share type access interface."""
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
@ -28,13 +29,23 @@ class ShareTypeAccessManager(base.ManagerWithFind):
resource_class = ShareTypeAccess
def list(self, share_type):
def _do_list(self, share_type, action_name="share_type_access"):
if share_type.is_public:
return None
return self._list(
'/types/%s/os-share-type-access' % common_base.getid(share_type),
'share_type_access')
"/types/%(st_id)s/%(action_name)s" % {
"st_id": common_base.getid(share_type),
"action_name": action_name},
"share_type_access")
@api_versions.wraps("1.0", "2.6")
def list(self, share_type):
return self._do_list(share_type, "os-share-type-access")
@api_versions.wraps("2.7") # noqa
def list(self, share_type):
return self._do_list(share_type, "share_type_access")
def add_project_access(self, share_type, project):
"""Add a project to the given share type access list."""

View File

@ -18,6 +18,7 @@
Share Type interface.
"""
from manilaclient import api_versions
from manilaclient import base
from manilaclient.openstack.common.apiclient import base as common_base
@ -38,8 +39,10 @@ class ShareType(common_base.Resource):
@property
def is_public(self):
"""Provide a user-friendly accessor to os-share-type-access."""
return self._info.get("os-share-type-access:is_public", 'N/A')
"""Provide a user-friendly accessor to [os-]share-type-access."""
return self._info.get(
"share_type_access:is_public",
self._info.get("os-share-type-access:is_public", "N/A"))
def get_keys(self, prefer_resource_data=True):
"""Get extra specs from a share type.
@ -130,8 +133,9 @@ class ShareTypeManager(base.ManagerWithFind):
"""
self._delete("/types/%s" % common_base.getid(share_type))
def create(self, name, spec_driver_handles_share_servers,
spec_snapshot_support=True, is_public=True):
def _do_create(self, name, spec_driver_handles_share_servers,
spec_snapshot_support=True, is_public=True,
is_public_keyname="os-share-type-access:is_public"):
"""Create a share type.
:param name: Descriptive name of the share type
@ -141,7 +145,7 @@ class ShareTypeManager(base.ManagerWithFind):
body = {
"share_type": {
"name": name,
"os-share-type-access:is_public": is_public,
is_public_keyname: is_public,
"extra_specs": {
"driver_handles_share_servers":
spec_driver_handles_share_servers,
@ -151,3 +155,23 @@ class ShareTypeManager(base.ManagerWithFind):
}
return self._create("/types", body, "share_type")
@api_versions.wraps("1.0", "2.6")
def create(self, name, spec_driver_handles_share_servers,
spec_snapshot_support=True, is_public=True):
return self._do_create(
name,
spec_driver_handles_share_servers,
spec_snapshot_support,
is_public,
"os-share-type-access:is_public")
@api_versions.wraps("2.7") # noqa
def create(self, name, spec_driver_handles_share_servers,
spec_snapshot_support=True, is_public=True):
return self._do_create(
name,
spec_driver_handles_share_servers,
spec_snapshot_support,
is_public,
"share_type_access:is_public")

View File

@ -21,6 +21,7 @@ try:
except ImportError:
from urllib.parse import urlencode # noqa
from manilaclient import api_versions
from manilaclient import base
from manilaclient.common import constants
from manilaclient import exceptions
@ -185,7 +186,7 @@ class ShareManager(base.ManagerWithFind):
}
return self._create('/shares', {'share': body}, 'share')
def migrate_share(self, share, host, force_host_copy):
def _do_migrate_share(self, share, host, force_host_copy, action_name):
"""Migrate share to new host and pool.
:param share: The :class:'share' to migrate
@ -193,13 +194,24 @@ class ShareManager(base.ManagerWithFind):
:param force_host_copy: Skip driver optimizations
"""
return self._action('os-migrate_share',
share, {'host': host,
'force_host_copy': force_host_copy})
return self._action(
action_name, share,
{"host": host, "force_host_copy": force_host_copy})
def manage(self, service_host, protocol, export_path,
driver_options=None, share_type=None,
name=None, description=None):
@api_versions.wraps("2.5", "2.6")
def migrate_share(self, share, host, force_host_copy):
return self._do_migrate_share(
share, host, force_host_copy, "os-migrate_share")
@api_versions.wraps("2.7") # noqa
def migrate_share(self, share, host, force_host_copy):
return self._do_migrate_share(
share, host, force_host_copy, "migrate_share")
def _do_manage(self, service_host, protocol, export_path,
driver_options=None, share_type=None,
name=None, description=None,
resource_path="/shares/manage"):
"""Manage some existing share.
:param service_host: text - host of share service where share is runing
@ -220,8 +232,23 @@ class ShareManager(base.ManagerWithFind):
'name': name,
'description': description
}
return self._create('/os-share-manage', {'share': body}, 'share')
return self._create(resource_path, {'share': body}, 'share')
@api_versions.wraps("1.0", "2.6")
def manage(self, service_host, protocol, export_path, driver_options=None,
share_type=None, name=None, description=None):
return self._do_manage(
service_host, protocol, export_path, driver_options, share_type,
name, description, "/os-share-manage")
@api_versions.wraps("2.7") # noqa
def manage(self, service_host, protocol, export_path, driver_options=None,
share_type=None, name=None, description=None):
return self._do_manage(
service_host, protocol, export_path, driver_options, share_type,
name, description, "/shares/manage")
@api_versions.wraps("1.0", "2.6")
def unmanage(self, share):
"""Unmanage a share.
@ -230,6 +257,14 @@ class ShareManager(base.ManagerWithFind):
return self.api.client.post(
"/os-share-unmanage/%s/unmanage" % common_base.getid(share))
@api_versions.wraps("2.7") # noqa
def unmanage(self, share):
"""Unmanage a share.
:param share: either share object or text with its ID.
"""
return self._action("unmanage", share)
def get(self, share):
"""Get a share.
@ -334,14 +369,22 @@ class ShareManager(base.ManagerWithFind):
url += "?consistency_group_id=%s" % consistency_group_id
self._delete(url)
def force_delete(self, share):
def _do_force_delete(self, share, action_name):
"""Delete a share forcibly - share status will be avoided.
:param share: either share object or text with its ID.
"""
return self._action('os-force_delete', common_base.getid(share))
return self._action(action_name, share)
def allow(self, share, access_type, access, access_level):
@api_versions.wraps("1.0", "2.6")
def force_delete(self, share):
return self._do_force_delete(share, "os-force_delete")
@api_versions.wraps("2.7") # noqa
def force_delete(self, share):
return self._do_force_delete(share, "force_delete")
def _do_allow(self, share, access_type, access, access_level, action_name):
"""Allow access to a share.
:param share: either share object or text with its ID.
@ -355,31 +398,57 @@ class ShareManager(base.ManagerWithFind):
}
if access_level:
access_params['access_level'] = access_level
access = self._action('os-allow_access', share,
access = self._action(action_name, share,
access_params)[1]["access"]
return access
def deny(self, share, access_id):
@api_versions.wraps("1.0", "2.6")
def allow(self, share, access_type, access, access_level):
return self._do_allow(
share, access_type, access, access_level, "os-allow_access")
@api_versions.wraps("2.7") # noqa
def allow(self, share, access_type, access, access_level):
return self._do_allow(
share, access_type, access, access_level, "allow_access")
def _do_deny(self, share, access_id, action_name):
"""Deny access to a share.
:param share: either share object or text with its ID.
:param access_id: ID of share access rule
"""
return self._action('os-deny_access', share, {'access_id': access_id})
return self._action(action_name, share, {"access_id": access_id})
def access_list(self, share):
@api_versions.wraps("1.0", "2.6")
def deny(self, share, access_id):
return self._do_deny(share, access_id, "os-deny_access")
@api_versions.wraps("2.7") # noqa
def deny(self, share, access_id):
return self._do_deny(share, access_id, "deny_access")
def _do_access_list(self, share, action_name):
"""Get access list to a share.
:param share: either share object or text with its ID.
"""
access_list = self._action("os-access_list", share)[1]["access_list"]
access_list = self._action(action_name, share)[1]["access_list"]
if access_list:
t = collections.namedtuple('Access', list(access_list[0]))
return [t(*value.values()) for value in access_list]
else:
return []
@api_versions.wraps("1.0", "2.6")
def access_list(self, share):
return self._do_access_list(share, "os-access_list")
@api_versions.wraps("2.7") # noqa
def access_list(self, share):
return self._do_access_list(share, "access_list")
def get_metadata(self, share):
"""Get metadata of a share.
@ -432,29 +501,53 @@ class ShareManager(base.ManagerWithFind):
url = '/shares/%s/action' % common_base.getid(share)
return self.api.client.post(url, body=body)
def reset_state(self, share, state):
def _do_reset_state(self, share, state, action_name):
"""Update the provided share with the provided state.
:param share: either share object or text with its ID.
:param state: text with new state to set for share.
"""
return self._action('os-reset_status', share, {'status': state})
return self._action(action_name, share, {"status": state})
def extend(self, share, new_size):
@api_versions.wraps("1.0", "2.6")
def reset_state(self, share, state):
return self._do_reset_state(share, state, "os-reset_status")
@api_versions.wraps("2.7") # noqa
def reset_state(self, share, state):
return self._do_reset_state(share, state, "reset_status")
def _do_extend(self, share, new_size, action_name):
"""Extend the size of the specified share.
:param share: either share object or text with its ID.
:param new_size: The desired size to extend share to.
"""
return self._action('os-extend', share, {'new_size': new_size})
return self._action(action_name, share, {"new_size": new_size})
def shrink(self, share, new_size):
@api_versions.wraps("1.0", "2.6")
def extend(self, share, new_size):
return self._do_extend(share, new_size, "os-extend")
@api_versions.wraps("2.7") # noqa
def extend(self, share, new_size):
return self._do_extend(share, new_size, "extend")
def _do_shrink(self, share, new_size, action_name):
"""Shrink the size of the specified share.
:param share: either share object or text with its ID.
:param new_size: The desired size to shrink share to.
"""
return self._action('os-shrink', share, {'new_size': new_size})
return self._action(action_name, share, {'new_size': new_size})
@api_versions.wraps("1.0", "2.6")
def shrink(self, share, new_size):
return self._do_shrink(share, new_size, "os-shrink")
@api_versions.wraps("2.7") # noqa
def shrink(self, share, new_size):
return self._do_shrink(share, new_size, "shrink")
def list_instances(self, share):
"""List instances of the specified share.